source: Dev/branches/rest-dojo-ui/client/dojox/gfx/canvasWithEvents.js @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

File size: 20.4 KB
Line 
1define(["dojo/_base/lang", "dojo/_base/declare", "dojo/_base/connect", "dojo/_base/Color", "dojo/dom",
2                "dojo/dom-geometry", "./_base","./canvas", "./shape", "./matrix"],
3  function(lang, declare, hub, Color, dom, domGeom, g, canvas, shapeLib, m){
4/*=====
5        dojox.gfx.canvasWithEvents = {
6        // module:
7        //              dojox/gfx/canvasWithEvents
8        // summary:
9        //              This the graphics rendering bridge for W3C Canvas compliant browsers which extends
10        //              the basic canvas drawing renderer bridge to add additional support for graphics events
11        //              on Shapes.
12        //              Since Canvas is an immediate mode graphics api, with no object graph or
13        //              eventing capabilities, use of the canvas module alone will only add in drawing support.
14        //              This additional module, canvasWithEvents extends this module with additional support
15        //              for handling events on Canvas.  By default, the support for events is now included
16        //              however, if only drawing capabilities are needed, canvas event module can be disabled
17        //              using the dojoConfig option, canvasEvents:true|false.
18        //              The id of the Canvas renderer is 'canvasWithEvents'.  This id can be used when switch Dojo's
19        //              graphics context between renderer implementations.  See dojox.gfx._base switchRenderer
20        //              API.   
21        };
22        g = dojox.gfx;
23        canvas.Shape = dojox.gfx.canvas.Shape;
24        canvas.Group = dojox.gfx.canvas.Group;
25        canvas.Image = dojox.gfx.canvas.Image;
26        canvas.Text = dojox.gfx.canvas.Text;
27        canvas.Rect = dojox.gfx.canvas.Rect;
28        canvas.Circle = dojox.gfx.canvas.Circle;
29        canvas.Ellipse = dojox.gfx.canvas.Ellipse;
30        canvas.Line = dojox.gfx.canvas.Line;
31        canvas.PolyLine = dojox.gfx.canvas.PolyLine;
32        canvas.TextPath = dojox.gfx.canvas.TextPath;
33        canvas.Path = dojox.gfx.canvas.Path;
34        canvas.Surface = dojox.gfx.canvas.Surface;
35        canvasEvent.Shape = dojox.gfx.canvasWithEvents.Shape;
36       
37  =====*/
38        var canvasEvent = g.canvasWithEvents = {};
39
40        declare("dojox.gfx.canvasWithEvents.Shape", canvas.Shape, {
41               
42                _testInputs: function(/* Object */ctx, /* Array */ pos){
43                        if (!this.canvasFill && this.strokeStyle) {
44                                // pixel-based until a getStrokedPath-like api is available on the path
45                                this._hitTestPixel(ctx, pos);
46                        } else {
47                                this._renderShape(ctx);
48                                var cnt = pos.length, t = this.getTransform();
49                                for (var i = 0; i < pos.length; ++i) {
50                                        var input = pos[i];
51                                        // already hit
52                                        if (input.target)
53                                                continue;
54                                        var x = input.x, y = input.y;
55                                        var p = t ? m.multiplyPoint(m.invert(t), x, y) : {
56                                                x: x,
57                                                y: y
58                                        };
59                                        input.target = this._hitTestGeometry(ctx, p.x, p.y);
60                                }
61                        }
62                },
63                _hitTestPixel: function(/* Object */ctx, /* Array */ pos){
64                        for (var i = 0; i < pos.length; ++i) {
65                                var input = pos[i];
66                                if (input.target)
67                                        continue;
68                                var x = input.x, y = input.y;
69                                ctx.clearRect(0,0,1,1);
70                                ctx.save();
71                                ctx.translate(-x, -y);
72                                this._render(ctx, true);
73                                input.target = ctx.getImageData(0, 0, 1, 1).data[0] ? this : null;
74                                ctx.restore();
75                        }
76                },
77                _hitTestGeometry: function(ctx, x, y){
78                        return ctx.isPointInPath(x, y) ? this : null;
79                },             
80               
81                _renderFill: function(/* Object */ ctx, /* Boolean */ apply){
82                        // summary:
83                        //              render fill for the shape
84                        // ctx:
85                        //              a canvas context object
86                        // apply:
87                        //              whether ctx.fill() shall be called
88                        if(ctx.pickingMode){
89                                if("canvasFill" in this && apply){ ctx.fill(); }
90                                return;
91                        }
92                        this.inherited(arguments);
93                },
94                _renderStroke: function(/* Object */ ctx, /* Boolean */ apply){
95                        // summary:
96                        //              render stroke for the shape
97                        // ctx:
98                        //              a canvas context object
99                        // apply:
100                        //              whether ctx.stroke() shall be called
101                        if (this.strokeStyle && ctx.pickingMode) {
102                                var c = this.strokeStyle.color;
103                                try {
104                                        this.strokeStyle.color = new Color(ctx.strokeStyle);
105                                        this.inherited(arguments);
106                                } finally {
107                                        this.strokeStyle.color = c;
108                                }
109                        } else{
110                                this.inherited(arguments);                             
111                        }
112                },
113               
114                // events
115               
116                getEventSource: function(){
117                        // summary: returns this gfx shape event source, which is the surface rawnode in the case of canvas.
118                       
119                        return this.surface.getEventSource();
120                },
121               
122                connect: function(name, object, method){
123                        // summary: connects a handler to an event on this shape
124                        this.surface._setupEvents(name); // setup events on demand
125                        // No need to fix callback. The listeners registered by
126                        // '_setupEvents()' are always invoked first and they
127                        // already 'fix' the event
128                        return arguments.length > 2 ? // Object
129                                         hub.connect(this, name, object, method) : hub.connect(this, name, object);
130                },
131                disconnect: function(token){
132                        // summary: disconnects an event handler
133                        hub.disconnect(token);
134                },
135                // connect hook
136                oncontextmenu:  function(){},
137                onclick:        function(){},
138                ondblclick:     function(){},
139                onmouseenter:   function(){},
140                onmouseleave:   function(){},
141                onmouseout:     function(){},
142                onmousedown:    function(){},
143                ontouchstart:   function(){},
144                touchstart:     function(){},
145                onmouseup:      function(){},
146                ontouchend:     function(){},
147                touchend:       function(){},
148                onmouseover:    function(){},
149                onmousemove:    function(){},
150                ontouchmove:    function(){},
151                touchmove:      function(){},
152                onkeydown:      function(){},
153                onkeyup:        function(){}
154        });
155       
156        declare("dojox.gfx.canvasWithEvents.Group", [canvasEvent.Shape, canvas.Group], {
157                _testInputs: function(/*Object*/ctx, /*Array*/ pos){
158                        var children = this.children, t = this.getTransform(), i, j;
159                        if(children.length == 0){
160                                return;
161                        }
162                        var posbk = [];
163                        for(i = 0; i < pos.length; ++i){
164                                var input = pos[i];
165                                // backup position before transform applied
166                                posbk[i] = {
167                                        x: input.x,
168                                        y: input.y
169                                };
170                                if(input.target) continue;
171                                var x = input.x, y = input.y;
172                                var p = t ? m.multiplyPoint(m.invert(t), x, y) : {
173                                        x: x,
174                                        y: y
175                                };
176                                input.x = p.x;
177                                input.y = p.y;
178                        }
179                        for(i = children.length - 1; i >= 0; --i){
180                                children[i]._testInputs(ctx, pos);
181                                // does it need more hit tests ?
182                                var allFound = true;
183                                for(j = 0; j < pos.length; ++j){
184                                        if(pos[j].target == null){
185                                                allFound = false;
186                                                break;
187                                        }
188                                }
189                                if(allFound){
190                                        break;
191                                }
192                        }
193                        for(i = 0; i < pos.length; ++i){
194                                pos[i].x = posbk[i].x;
195                                pos[i].y = posbk[i].y;
196                        }       
197                }       
198        });
199       
200        declare("dojox.gfx.canvasWithEvents.Image", [canvasEvent.Shape, canvas.Image], {
201                _renderShape: function(/* Object */ ctx){
202                        // summary:
203                        //              render image
204                        // ctx:
205                        //              a canvas context object
206                        var s = this.shape;
207                        if(ctx.pickingMode){
208                                ctx.fillRect(s.x, s.y, s.width, s.height);
209                        }else{
210                                this.inherited(arguments);
211                        }
212                },
213               
214                _hitTestGeometry: function(ctx, x, y){
215                        // TODO: improve hit testing to take into account transparency
216                        var s = this.shape;
217                        return x >= s.x && x <= s.x + s.width && y >= s.y && y <= s.y + s.height ? this : null;
218                }
219        });
220       
221        declare("dojox.gfx.canvasWithEvents.Text", [canvasEvent.Shape, canvas.Text], {
222                _testInputs: function(ctx, pos){
223                        return this._hitTestPixel(ctx, pos);
224                }
225        });
226
227
228        declare("dojox.gfx.canvasWithEvents.Rect", [canvasEvent.Shape, canvas.Rect], {});
229        declare("dojox.gfx.canvasWithEvents.Circle", [canvasEvent.Shape, canvas.Circle], {});
230        declare("dojox.gfx.canvasWithEvents.Ellipse", [canvasEvent.Shape, canvas.Ellipse],{});
231        declare("dojox.gfx.canvasWithEvents.Line", [canvasEvent.Shape, canvas.Line],{});
232        declare("dojox.gfx.canvasWithEvents.Polyline", [canvasEvent.Shape, canvas.Polyline],{});
233        declare("dojox.gfx.canvasWithEvents.Path", [canvasEvent.Shape, canvas.Path],{});
234        declare("dojox.gfx.canvasWithEvents.TextPath", [canvasEvent.Shape, canvas.TextPath],{});
235
236       
237        // a map that redirects shape-specific events to the canvas event handler that deals with these events
238        var _eventsRedirectMap = {
239                onmouseenter : 'onmousemove',
240                onmouseleave : 'onmousemove',
241                onmouseout   : 'onmousemove',
242                onmouseover  : 'onmousemove',
243                touchstart   : 'ontouchstart',
244                touchend     : 'ontouchend',
245                touchmove    : 'ontouchmove'
246        };
247        var _eventsShortNameMap = {
248                ontouchstart   : 'touchstart',
249                ontouchend     : 'touchend',
250                ontouchmove    : 'touchmove'
251        };
252       
253        var uagent = navigator.userAgent.toLowerCase(),
254                isiOS = uagent.search('iphone') > -1 ||
255                            uagent.search('ipad') > -1 ||
256                                uagent.search('ipod') > -1;
257       
258        declare("dojox.gfx.canvasWithEvents.Surface", canvas.Surface, {
259                constructor:function(){
260                        this._pick = { curr: null, last: null };
261                        this._pickOfMouseDown = null;
262                        this._pickOfMouseUp = null;
263                },
264               
265                connect: function(/*String*/name, /*Object*/object, /*Function|String*/method){
266                        // summary: connects a handler to an event on this surface
267                        // name : String
268                        //              The event name
269                        // object: Object
270                        //              The object that method will receive as "this".
271                        // method: Function
272                        //              A function reference, or name of a function in context.
273                         
274                        if (name.indexOf('touch') !== -1) {
275                                // in case of surface.connect('touchXXX'...), we must root the handler to the
276                                // specific touch event processing (done in fireTouchEvents) so that the event is properly configured.
277                                // So, we activate the shape-level event processing calling _setupEvents,
278                                // and connect to the _ontouchXXXImpl_ hooks that are called back by invokeHandler()
279                                this._setupEvents(name);
280                                name = "_on" + name + "Impl_";
281                                return hub.connect(this, name, object, method);
282                        } else {
283                                this._initMirrorCanvas();
284                                return hub.connect(this.getEventSource(), name, null,
285                                                        shapeLib.fixCallback(this, g.fixTarget, object, method));
286                        }       
287                },
288
289                // connection hooks for touch events connect
290                _ontouchstartImpl_: function(){},
291                _ontouchendImpl_:   function(){},
292                _ontouchmoveImpl_:  function(){},
293               
294                _initMirrorCanvas: function(){
295                        if (!this.mirrorCanvas) {
296                                var p = this._parent, mirror = p.ownerDocument.createElement("canvas");
297                                mirror.width = 1;
298                                mirror.height = 1;
299                                mirror.style.position = 'absolute';
300                                mirror.style.left = '-99999px';
301                                mirror.style.top = '-99999px';
302                                p.appendChild(mirror);
303                                this.mirrorCanvas = mirror;
304                        }
305                },
306
307                _setupEvents: function(eventName){
308                        // summary:
309                        //              setup event listeners if not yet
310
311                        // onmouseenter and onmouseleave shape events are handled in the onmousemove surface handler
312                        if (eventName in _eventsRedirectMap)
313                                eventName = _eventsRedirectMap[eventName];
314                        if (this._eventsH && this._eventsH[eventName]) {
315                                // the required listener has already been connected
316                                return;
317                        }
318                        // a mirror canvas for shape picking
319                        this._initMirrorCanvas();
320                        if (!this._eventsH)
321                                this._eventsH = {};
322                        // register event hooks if not done yet
323                        this._eventsH[eventName] = hub.connect(this.getEventSource(), eventName,
324                                        shapeLib.fixCallback(this, g.fixTarget, this, "_" + eventName));
325                        if (eventName === 'onclick' || eventName==='ondblclick') {
326                                if(!this._eventsH['onmousedown']){
327                                        this._eventsH['onmousedown'] = hub.connect(this.getEventSource(),
328                                                        'onmousedown', shapeLib.fixCallback(this, g.fixTarget, this, "_onmousedown"));
329                                }
330                                if(!this._eventsH['onmouseup']){
331                                        this._eventsH['onmouseup'] = hub.connect(this.getEventSource(),
332                                                        'onmouseup', shapeLib.fixCallback(this, g.fixTarget, this, "_onmouseup"));
333                                }
334                        }                       
335                },
336               
337                destroy: function(){
338                        // summary: stops the move, deletes all references, so the object can be garbage-collected
339                        canvas.Surface.destroy.apply(this);
340                       
341                        // destroy events and objects
342                        for(var i in this._eventsH){
343                                hub.disconnect(this._eventsH[i]);
344                        }
345                        this._eventsH = this.mirrorCanvas = null;
346                },     
347               
348                // events
349                getEventSource: function(){
350                        // summary: returns the canvas DOM node for surface-level events
351                        return this.rawNode;
352                },
353
354                // internal handlers used to implement shape-level event notification
355                _invokeHandler: function(base, method, event){
356                        // Invokes handler function
357                        var handler = base[method];
358                        if(handler && handler.after){
359                                handler.apply(base, [event]);
360                        }else if (method in _eventsShortNameMap){
361                                // there may be a synonym event name (touchstart -> ontouchstart)
362                                handler = base[_eventsShortNameMap[method]];
363                                if(handler && handler.after){
364                                        handler.apply(base, [event]);
365                                }
366                        }
367                        if(!handler && method.indexOf('touch') !== -1){
368                                // special case for surface touch handlers
369                                method = "_" + method + "Impl_";
370                                handler = base[method];
371                                if(handler){
372                                        handler.apply(base, [event]);
373                                }
374                        }
375                        // Propagates event up in the DOM hierarchy only if event
376                        // has not been stopped (event.cancelBubble is true)
377                        if (!isEventStopped(event) && base.parent) {
378                                this._invokeHandler(base.parent, method, event);
379                        }
380                },
381                _oncontextmenu: function(e){
382                        // summary: triggers onclick
383                        // this._pick.curr = an array of target for touch event, one target instance for mouse events
384                        if(this._pick.curr){
385                                this._invokeHandler(this._pick.curr, 'oncontextmenu', e);
386                        }
387                },
388                _ondblclick: function(e){
389                        // summary: triggers onclick
390                        // this._pick.curr = an array of target for touch event, one target instance for mouse events
391                        if(this._pickOfMouseUp){
392                                this._invokeHandler(this._pickOfMouseUp, 'ondblclick', e);
393                        }
394                },
395                _onclick: function(e){
396                        // summary: triggers onclick
397                        // this._pick.curr = an array of target for touch event, one target instance for mouse events
398                        if(this._pickOfMouseUp && this._pickOfMouseUp == this._pickOfMouseDown){
399                                this._invokeHandler(this._pickOfMouseUp, 'onclick', e);
400                        }
401                },
402                _onmousedown: function(e){
403                        // summary: triggers onmousedown
404                        this._pickOfMouseDown = this._pick.curr;
405                        // this._pick.curr = an array of target for touch event, one target instance for mouse events
406                        if(this._pick.curr){
407                                this._invokeHandler(this._pick.curr, 'onmousedown', e);
408                        }
409                },
410                _ontouchstart: function(e){
411                        // summary: triggers ontouchstart                       
412                        // this._pick.curr = an array of target for touch event, one target instance for mouse events
413                        if (this._pick.curr) {
414                                this._fireTouchEvent(e);
415                        }
416                       
417                },
418                _onmouseup: function(e){
419                        // summary: triggers onmouseup
420                        // this._pick.curr = an array of target for touch event, one target instance for mouse events
421                        this._pickOfMouseUp = this._pick.curr;
422                        if(this._pick.curr){
423                                this._invokeHandler(this._pick.curr, 'onmouseup', e);
424                        }
425                },
426                _ontouchend: function(e){
427                        // summary: triggers ontouchend
428                        // this._pick.curr = an array of target for touch event, one target instance for mouse events
429                        if(this._pick.curr){
430                                for(var i = 0; i < this._pick.curr.length; ++i){
431                                        if(this._pick.curr[i].target){
432                                                e.gfxTarget = this._pick.curr[i].target;
433                                                this._invokeHandler(this._pick.curr[i].target, 'ontouchend', e);
434                                        }
435                                }
436                        }
437                },
438                _onmousemove: function(e){
439                        // summary: triggers onmousemove, onmouseenter, onmouseleave
440                        // this._pick.curr = an array of target for touch event, one target instance for mouse events
441                        if(this._pick.last && this._pick.last != this._pick.curr){
442                                this._invokeHandler(this._pick.last, 'onmouseleave', e);
443                                this._invokeHandler(this._pick.last, 'onmouseout', e);
444                        }
445                        if(this._pick.curr){
446                                if(this._pick.last == this._pick.curr){
447                                        this._invokeHandler(this._pick.curr, 'onmousemove', e);
448                                }else{
449                                        this._invokeHandler(this._pick.curr, 'onmouseenter', e);
450                                        this._invokeHandler(this._pick.curr, 'onmouseover', e);
451                                }
452                        }
453                },
454                _ontouchmove: function(e){
455                        // summary: triggers ontouchmove
456                        if(this._pick.curr){
457                                this._fireTouchEvent(e);
458                        }
459                },
460               
461                _fireTouchEvent: function(e){
462                        // this._pick.curr = an array of target for touch event, one target instance for mouse events
463                        var toFire = []; // the per-shape events list to fire
464                        // for each positive picking:
465                        // .group all pickings by target
466                        // .collect all touches for the picking target
467                        for(var i = 0; i < this._pick.curr.length; ++i){
468                                var pick = this._pick.curr[i];
469                                if(pick.target){
470                                        // touches for this target
471                                        var gfxtt = pick.target.__gfxtt;
472                                        if(!gfxtt){
473                                                gfxtt = [];
474                                                pick.target.__gfxtt = gfxtt;
475                                        }
476                                        // store the touch that yielded to this picking
477                                        gfxtt.push(pick.t);
478                                        // if the target has not been added yet, add it
479                                        if(!pick.target.__inToFire){
480                                                toFire.push(pick.target);
481                                                pick.target.__inToFire=true;
482                                        }
483                                }
484                        }
485                        if(toFire.length === 0){
486                                // no target, invokes the surface handler
487                                this._invokeHandler(this, 'on' + e.type, e);
488                        }else{
489                                for(i = 0; i < toFire.length; ++i){
490                                        (function(){
491                                                var targetTouches = toFire[i].__gfxtt;
492                                                // fires the original event BUT with our own targetTouches array.
493                                                // Note for iOS:
494                                                var evt = lang.delegate(e, {gfxTarget: toFire[i]});
495                                                if(isiOS){
496                                                        // must use the original preventDefault function or iOS will throw a TypeError
497                                                        evt.preventDefault = function(){e.preventDefault();};
498                                                        evt.stopPropagation = function(){e.stopPropagation();};
499                                                }
500                                                // override targetTouches with the filtered one
501                                                evt.__defineGetter__('targetTouches', function(){return targetTouches;});
502                                                // clean up
503                                                delete toFire[i].__gfxtt;
504                                                delete toFire[i].__inToFire;
505                                                // fire event
506                                                this._invokeHandler(toFire[i], 'on' + e.type, evt);
507                                        }).call(this);
508                                }
509                        }
510                },
511                _onkeydown: function(){},       // needed?
512                _onkeyup:   function(){},       // needed?
513
514                _whatsUnderEvent: function(evt){
515                        // summary:     returns the shape under the mouse event
516                        // evt:         mouse event
517                       
518                        var surface = this, i,
519                                pos = domGeom.position(surface.rawNode, true),
520                                inputs = [], changedTouches = evt.changedTouches, touches = evt.touches;
521                        // collect input events targets
522                        if(changedTouches){
523                                for(i = 0; i < changedTouches.length; ++i){
524                                        inputs.push({
525                                                t: changedTouches[i],
526                                                x: changedTouches[i].pageX - pos.x,
527                                                y: changedTouches[i].pageY - pos.y
528                                        });
529                                }
530                        }else if(touches){
531                                for(i = 0; i < touches.length; ++i){
532                                        inputs.push({
533                                                t: touches[i],
534                                                x: touches[i].pageX - pos.x,
535                                                y: touches[i].pageY - pos.y
536                                        });
537                                }
538                        }else{
539                                inputs.push({
540                                        x : evt.pageX - pos.x,
541                                        y : evt.pageY - pos.y
542                                });
543                        }
544                               
545                        var mirror = surface.mirrorCanvas,
546                                ctx = mirror.getContext('2d'),
547                                children = surface.children;
548                       
549                        ctx.clearRect(0, 0, mirror.width, mirror.height);
550                        ctx.save();
551                        ctx.strokeStyle = "rgba(127,127,127,1.0)";
552                        ctx.fillStyle = "rgba(127,127,127,1.0)";
553                        ctx.pickingMode = true;
554                        var pick = null;
555                        // process the inputs to find the target.
556                        for(i = children.length-1; i >= 0; i--){
557                                children[i]._testInputs(ctx, inputs);
558                                // does it need more hit tests ?
559                                var allFound = true;
560                                for(j = 0; j < inputs.length; ++j){
561                                        if(inputs[j].target == null){
562                                                allFound = false;
563                                                break;
564                                        }
565                                }
566                                if(allFound){
567                                        break;
568                                }
569                        }
570                        ctx.restore();
571                        // touch event handlers expect an array of target, mouse handlers one target
572                        return (touches || changedTouches) ? inputs : inputs[0].target;
573                }               
574        });
575       
576        canvasEvent.createSurface = function(parentNode, width, height){
577                // summary: creates a surface (Canvas)
578                // parentNode: Node: a parent node
579                // width: String: width of surface, e.g., "100px"
580                // height: String: height of surface, e.g., "100px"
581
582                if(!width && !height){
583                        var pos = domGeom.position(parentNode);
584                        width  = width  || pos.w;
585                        height = height || pos.h;
586                }
587                if(typeof width == "number"){
588                        width = width + "px";
589                }
590                if(typeof height == "number"){
591                        height = height + "px";
592                }
593
594                var s = new canvasEvent.Surface(),
595                        p = dom.byId(parentNode),
596                        c = p.ownerDocument.createElement("canvas");
597
598                c.width  = g.normalizedLength(width);   // in pixels
599                c.height = g.normalizedLength(height);  // in pixels
600
601                p.appendChild(c);
602                s.rawNode = c;
603                s._parent = p;
604                s.surface = s;
605                return s;       // dojox.gfx.Surface
606        };
607
608
609        // Mouse/Touch event
610        var isEventStopped = function(/*Event*/ evt){
611                // summary:
612                //    queries whether an event has been stopped or not
613                // evt: Event
614                //    The event object.
615                if(evt.cancelBubble !== undefined){
616                        return evt.cancelBubble;
617                }
618                return false;
619        };
620       
621        canvasEvent.fixTarget = function(event, gfxElement){
622                // summary:
623                //     Adds the gfxElement to event.gfxTarget if none exists. This new
624                //     property will carry the GFX element associated with this event.
625                // event: Object
626                //     The current input event (MouseEvent or TouchEvent)
627                // gfxElement: Object
628                //     The GFX target element (a Surface in this case)
629                if(isEventStopped(event)){
630                        return false;
631                }
632                if(!event.gfxTarget){
633                        gfxElement._pick.last = gfxElement._pick.curr;
634                        gfxElement._pick.curr = gfxElement._whatsUnderEvent(event);
635                        if (!lang.isArray(gfxElement._pick.curr))
636                                event.gfxTarget = gfxElement._pick.curr;
637                }
638                return true;
639        };
640
641        return canvasEvent;
642});
Note: See TracBrowser for help on using the repository browser.