~bac/juju-gui/trunkcopy

« back to all changes in this revision

Viewing changes to lib/yui/build/graphics-canvas/graphics-canvas.js

  • Committer: kapil.foss at gmail
  • Date: 2012-07-13 18:45:59 UTC
  • Revision ID: kapil.foss@gmail.com-20120713184559-2xl7be17egsrz0c9
reshape

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
YUI 3.5.1 (build 22)
3
 
Copyright 2012 Yahoo! Inc. All rights reserved.
4
 
Licensed under the BSD License.
5
 
http://yuilibrary.com/license/
6
 
*/
7
 
YUI.add('graphics-canvas', function(Y) {
8
 
 
9
 
var SHAPE = "canvasShape",
10
 
    DOCUMENT = Y.config.doc,
11
 
    Y_LANG = Y.Lang,
12
 
    AttributeLite = Y.AttributeLite,
13
 
        CanvasShape,
14
 
        CanvasPath,
15
 
        CanvasRect,
16
 
    CanvasEllipse,
17
 
        CanvasCircle,
18
 
    CanvasPieSlice,
19
 
    Y_Color = Y.Color,
20
 
    PARSE_INT = parseInt,
21
 
    PARSE_FLOAT = parseFloat,
22
 
    IS_NUMBER = Y_LANG.isNumber,
23
 
    RE = RegExp,
24
 
    TORGB = Y_Color.toRGB,
25
 
    TOHEX = Y_Color.toHex;
26
 
 
27
 
/**
28
 
 * <a href="http://www.w3.org/TR/html5/the-canvas-element.html">Canvas</a> implementation of the <a href="Drawing.html">`Drawing`</a> class. 
29
 
 * `CanvasDrawing` is not intended to be used directly. Instead, use the <a href="Drawing.html">`Drawing`</a> class. 
30
 
 * If the browser lacks <a href="http://www.w3.org/TR/SVG/">SVG</a> capabilities but has 
31
 
 * <a href="http://www.w3.org/TR/html5/the-canvas-element.html">Canvas</a> capabilities, the <a href="Drawing.html">`Drawing`</a> 
32
 
 * class will point to the `CanvasDrawing` class.
33
 
 *
34
 
 * @module graphics
35
 
 * @class CanvasDrawing
36
 
 * @constructor
37
 
 */
38
 
function CanvasDrawing()
39
 
{
40
 
}
41
 
 
42
 
CanvasDrawing.prototype = {
43
 
    /**
44
 
     * Parses hex color string and alpha value to rgba
45
 
     *
46
 
     * @method _toRGBA
47
 
     * @param {Object} val Color value to parse. Can be hex string, rgb or name.
48
 
     * @param {Number} alpha Numeric value between 0 and 1 representing the alpha level.
49
 
     * @private
50
 
     */
51
 
    _toRGBA: function(val, alpha) {
52
 
        alpha = (alpha !== undefined) ? alpha : 1;
53
 
        if (!Y_Color.re_RGB.test(val)) {
54
 
            val = TOHEX(val);
55
 
        }
56
 
 
57
 
        if(Y_Color.re_hex.exec(val)) {
58
 
            val = 'rgba(' + [
59
 
                PARSE_INT(RE.$1, 16),
60
 
                PARSE_INT(RE.$2, 16),
61
 
                PARSE_INT(RE.$3, 16)
62
 
            ].join(',') + ',' + alpha + ')';
63
 
        }
64
 
        return val;
65
 
    },
66
 
 
67
 
    /**
68
 
     * Converts color to rgb format
69
 
     *
70
 
     * @method _toRGB
71
 
     * @param val Color value to convert.
72
 
     * @private 
73
 
     */
74
 
    _toRGB: function(val) {
75
 
        return TORGB(val);
76
 
    },
77
 
 
78
 
    /**
79
 
     * Sets the size of the graphics object.
80
 
     * 
81
 
     * @method setSize
82
 
     * @param w {Number} width to set for the instance.
83
 
     * @param h {Number} height to set for the instance.
84
 
     * @private
85
 
     */
86
 
        setSize: function(w, h) {
87
 
        if(this.get("autoSize"))
88
 
        {
89
 
            if(w > this.node.getAttribute("width"))
90
 
            {
91
 
                this.node.style.width = w + "px";
92
 
                this.node.setAttribute("width", w);
93
 
            }
94
 
            if(h > this.node.getAttribute("height"))
95
 
            {
96
 
                this.node.style.height = h + "px";
97
 
                this.node.setAttribute("height", h);
98
 
            }
99
 
        }
100
 
    },
101
 
    
102
 
        /**
103
 
     * Tracks coordinates. Used to calculate the start point of dashed lines. 
104
 
     *
105
 
     * @method _updateCoords
106
 
     * @param {Number} x x-coordinate
107
 
     * @param {Number} y y-coordinate
108
 
         * @private
109
 
         */
110
 
    _updateCoords: function(x, y)
111
 
    {
112
 
        this._xcoords.push(x);
113
 
        this._ycoords.push(y);
114
 
    },
115
 
 
116
 
        /**
117
 
     * Clears the coordinate arrays. Called at the end of a drawing operation.  
118
 
         * 
119
 
     * @method _clearAndUpdateCoords
120
 
     * @private
121
 
         */
122
 
    _clearAndUpdateCoords: function()
123
 
    {
124
 
        var x = this._xcoords.pop() || 0,
125
 
            y = this._ycoords.pop() || 0;
126
 
        this._updateCoords(x, y);
127
 
    },
128
 
 
129
 
        /**
130
 
     * Moves the shape's dom node.
131
 
     *
132
 
     * @method _updateNodePosition
133
 
         * @private
134
 
         */
135
 
    _updateNodePosition: function()
136
 
    {
137
 
        var node = this.get("node"),
138
 
            x = this.get("x"),
139
 
            y = this.get("y"); 
140
 
        node.style.position = "absolute";
141
 
        node.style.left = (x + this._left) + "px";
142
 
        node.style.top = (y + this._top) + "px";
143
 
    },
144
 
    
145
 
    /**
146
 
     * Queues up a method to be executed when a shape redraws.
147
 
     *
148
 
     * @method _updateDrawingQueue
149
 
     * @param {Array} val An array containing data that can be parsed into a method and arguments. The value at zero-index of the array is a string reference of
150
 
     * the drawing method that will be called. All subsequent indices are argument for that method. For example, `lineTo(10, 100)` would be structured as:
151
 
     * `["lineTo", 10, 100]`.
152
 
     * @private
153
 
     */
154
 
    _updateDrawingQueue: function(val)
155
 
    {
156
 
        this._methods.push(val);
157
 
    },
158
 
    
159
 
    /**
160
 
     * Draws a line segment using the current line style from the current drawing position to the specified x and y coordinates.
161
 
     * 
162
 
     * @method lineTo
163
 
     * @param {Number} point1 x-coordinate for the end point.
164
 
     * @param {Number} point2 y-coordinate for the end point.
165
 
     */
166
 
    lineTo: function(point1, point2, etc) 
167
 
    {
168
 
        var args = arguments, 
169
 
            i = 0, 
170
 
            len,
171
 
            x,
172
 
            y,
173
 
            wt = this._stroke && this._strokeWeight ? this._strokeWeight : 0;
174
 
        if(!this._lineToMethods)
175
 
        {
176
 
            this._lineToMethods = [];
177
 
        }
178
 
        if (typeof point1 === 'string' || typeof point1 === 'number') {
179
 
            args = [[point1, point2]];
180
 
        }
181
 
 
182
 
        len = args.length;
183
 
        for (; i < len; ++i) 
184
 
        {
185
 
            if(args[i])
186
 
            {
187
 
                x = args[i][0];
188
 
                y = args[i][1];
189
 
                this._updateDrawingQueue(["lineTo", x, y]);
190
 
                this._lineToMethods[this._lineToMethods.length] = this._methods[this._methods.length - 1];
191
 
                this._trackSize(x - wt, y - wt);
192
 
                this._trackSize(x + wt, y + wt);
193
 
                this._updateCoords(x, y);
194
 
            }
195
 
        }
196
 
        this._drawingComplete = false;
197
 
        return this;
198
 
    },
199
 
 
200
 
    /**
201
 
     * Moves the current drawing position to specified x and y coordinates.
202
 
     *
203
 
     * @method moveTo
204
 
     * @param {Number} x x-coordinate for the end point.
205
 
     * @param {Number} y y-coordinate for the end point.
206
 
     */
207
 
    moveTo: function(x, y) {
208
 
        var wt = this._stroke && this._strokeWeight ? this._strokeWeight : 0;
209
 
        this._updateDrawingQueue(["moveTo", x, y]);
210
 
        this._trackSize(x - wt, y - wt);
211
 
        this._trackSize(x + wt, y + wt);
212
 
        this._updateCoords(x, y);
213
 
        this._drawingComplete = false;
214
 
        return this;
215
 
    },
216
 
    
217
 
    /**
218
 
     * Draws a bezier curve.
219
 
     *
220
 
     * @method curveTo
221
 
     * @param {Number} cp1x x-coordinate for the first control point.
222
 
     * @param {Number} cp1y y-coordinate for the first control point.
223
 
     * @param {Number} cp2x x-coordinate for the second control point.
224
 
     * @param {Number} cp2y y-coordinate for the second control point.
225
 
     * @param {Number} x x-coordinate for the end point.
226
 
     * @param {Number} y y-coordinate for the end point.
227
 
     */
228
 
    curveTo: function(cp1x, cp1y, cp2x, cp2y, x, y) {
229
 
        var hiX,
230
 
            hiY,
231
 
            loX,
232
 
            loY;
233
 
        this._updateDrawingQueue(["bezierCurveTo", cp1x, cp1y, cp2x, cp2y, x, y]);
234
 
        this._drawingComplete = false;
235
 
        hiX = Math.max(x, Math.max(cp1x, cp2x));
236
 
        hiY = Math.max(y, Math.max(cp1y, cp2y));
237
 
        loX = Math.min(x, Math.min(cp1x, cp2x));
238
 
        loY = Math.min(y, Math.min(cp1y, cp2y));
239
 
        this._trackSize(hiX, hiY);
240
 
        this._trackSize(loX, loY);
241
 
        this._updateCoords(hiX, hiY);
242
 
        return this;
243
 
    },
244
 
 
245
 
    /**
246
 
     * Draws a quadratic bezier curve.
247
 
     *
248
 
     * @method quadraticCurveTo
249
 
     * @param {Number} cpx x-coordinate for the control point.
250
 
     * @param {Number} cpy y-coordinate for the control point.
251
 
     * @param {Number} x x-coordinate for the end point.
252
 
     * @param {Number} y y-coordinate for the end point.
253
 
     */
254
 
    quadraticCurveTo: function(cpx, cpy, x, y) {
255
 
        var hiX,
256
 
            hiY,
257
 
            loX,
258
 
            loY,
259
 
            wt = this._stroke && this._strokeWeight ? this._strokeWeight : 0;
260
 
        this._updateDrawingQueue(["quadraticCurveTo", cpx, cpy, x, y]);
261
 
        this._drawingComplete = false;
262
 
        hiX = Math.max(x, cpx);
263
 
        hiY = Math.max(y, cpy);
264
 
        loX = Math.min(x, cpx);
265
 
        loY = Math.min(y, cpy);
266
 
        this._trackSize(hiX + wt, hiY + wt);
267
 
        this._trackSize(loX - wt, loY - wt);
268
 
        this._updateCoords(hiX, hiY);
269
 
        return this;
270
 
    },
271
 
 
272
 
    /**
273
 
     * Draws a circle. Used internally by `CanvasCircle` class.
274
 
     *
275
 
     * @method drawCircle
276
 
     * @param {Number} x y-coordinate
277
 
     * @param {Number} y x-coordinate
278
 
     * @param {Number} r radius
279
 
     * @protected
280
 
     */
281
 
        drawCircle: function(x, y, radius) {
282
 
        var startAngle = 0,
283
 
            endAngle = 2 * Math.PI,
284
 
            wt = this._stroke && this._strokeWeight ? this._strokeWeight : 0,
285
 
            circum = radius * 2;
286
 
            circum += wt;
287
 
        this._drawingComplete = false;
288
 
        this._trackSize(x + circum, y + circum);
289
 
        this._trackSize(x - wt, y - wt);
290
 
        this._updateCoords(x, y);
291
 
        this._updateDrawingQueue(["arc", x + radius, y + radius, radius, startAngle, endAngle, false]);
292
 
        return this;
293
 
    },
294
 
 
295
 
    /**
296
 
     * Draws a diamond.     
297
 
     * 
298
 
     * @method drawDiamond
299
 
     * @param {Number} x y-coordinate
300
 
     * @param {Number} y x-coordinate
301
 
     * @param {Number} width width
302
 
     * @param {Number} height height
303
 
     * @protected
304
 
     */
305
 
    drawDiamond: function(x, y, width, height)
306
 
    {
307
 
        var midWidth = width * 0.5,
308
 
            midHeight = height * 0.5;
309
 
        this.moveTo(x + midWidth, y);
310
 
        this.lineTo(x + width, y + midHeight);
311
 
        this.lineTo(x + midWidth, y + height);
312
 
        this.lineTo(x, y + midHeight);
313
 
        this.lineTo(x + midWidth, y);
314
 
        return this;
315
 
    },
316
 
 
317
 
    /**
318
 
     * Draws an ellipse. Used internally by `CanvasEllipse` class.
319
 
     *
320
 
     * @method drawEllipse
321
 
     * @param {Number} x x-coordinate
322
 
     * @param {Number} y y-coordinate
323
 
     * @param {Number} w width
324
 
     * @param {Number} h height
325
 
     * @protected
326
 
     */
327
 
        drawEllipse: function(x, y, w, h) {
328
 
        var l = 8,
329
 
            theta = -(45/180) * Math.PI,
330
 
            angle = 0,
331
 
            angleMid,
332
 
            radius = w/2,
333
 
            yRadius = h/2,
334
 
            i = 0,
335
 
            centerX = x + radius,
336
 
            centerY = y + yRadius,
337
 
            ax, ay, bx, by, cx, cy,
338
 
            wt = this._stroke && this._strokeWeight ? this._strokeWeight : 0;
339
 
 
340
 
        ax = centerX + Math.cos(0) * radius;
341
 
        ay = centerY + Math.sin(0) * yRadius;
342
 
        this.moveTo(ax, ay);
343
 
        for(; i < l; i++)
344
 
        {
345
 
            angle += theta;
346
 
            angleMid = angle - (theta / 2);
347
 
            bx = centerX + Math.cos(angle) * radius;
348
 
            by = centerY + Math.sin(angle) * yRadius;
349
 
            cx = centerX + Math.cos(angleMid) * (radius / Math.cos(theta / 2));
350
 
            cy = centerY + Math.sin(angleMid) * (yRadius / Math.cos(theta / 2));
351
 
            this._updateDrawingQueue(["quadraticCurveTo", cx, cy, bx, by]);
352
 
        }
353
 
        this._trackSize(x + w + wt, y + h + wt);
354
 
        this._trackSize(x - wt, y - wt);
355
 
        this._updateCoords(x, y);
356
 
        return this;
357
 
    },
358
 
 
359
 
    /**
360
 
     * Draws a rectangle.
361
 
     *
362
 
     * @method drawRect
363
 
     * @param {Number} x x-coordinate
364
 
     * @param {Number} y y-coordinate
365
 
     * @param {Number} w width
366
 
     * @param {Number} h height
367
 
     */
368
 
    drawRect: function(x, y, w, h) {
369
 
        var wt = this._stroke && this._strokeWeight ? this._strokeWeight : 0;
370
 
        this._drawingComplete = false;
371
 
        this._updateDrawingQueue(["moveTo", x, y]);
372
 
        this._updateDrawingQueue(["lineTo", x + w, y]);
373
 
        this._updateDrawingQueue(["lineTo", x + w, y + h]);
374
 
        this._updateDrawingQueue(["lineTo", x, y + h]);
375
 
        this._updateDrawingQueue(["lineTo", x, y]);
376
 
        this._trackSize(x - wt, y - wt);
377
 
        this._trackSize(x + w + wt, y + h + wt);
378
 
        return this;
379
 
    },
380
 
 
381
 
    /**
382
 
     * Draws a rectangle with rounded corners.
383
 
     * 
384
 
     * @method drawRect
385
 
     * @param {Number} x x-coordinate
386
 
     * @param {Number} y y-coordinate
387
 
     * @param {Number} w width
388
 
     * @param {Number} h height
389
 
     * @param {Number} ew width of the ellipse used to draw the rounded corners
390
 
     * @param {Number} eh height of the ellipse used to draw the rounded corners
391
 
     */
392
 
    drawRoundRect: function(x, y, w, h, ew, eh) {
393
 
        var wt = this._stroke && this._strokeWeight ? this._strokeWeight : 0;
394
 
        this._drawingComplete = false;
395
 
        this._updateDrawingQueue(["moveTo", x, y + eh]);
396
 
        this._updateDrawingQueue(["lineTo", x, y + h - eh]);
397
 
        this._updateDrawingQueue(["quadraticCurveTo", x, y + h, x + ew, y + h]);
398
 
        this._updateDrawingQueue(["lineTo", x + w - ew, y + h]);
399
 
        this._updateDrawingQueue(["quadraticCurveTo", x + w, y + h, x + w, y + h - eh]);
400
 
        this._updateDrawingQueue(["lineTo", x + w, y + eh]);
401
 
        this._updateDrawingQueue(["quadraticCurveTo", x + w, y, x + w - ew, y]);
402
 
        this._updateDrawingQueue(["lineTo", x + ew, y]);
403
 
        this._updateDrawingQueue(["quadraticCurveTo", x, y, x, y + eh]);
404
 
        this._trackSize(x - wt, y - wt);
405
 
        this._trackSize(x + w + wt, y + h + wt);
406
 
        this._updateCoords(w, h);
407
 
        return this;
408
 
    },
409
 
    
410
 
    /**
411
 
     * Draws a wedge.
412
 
     *
413
 
     * @method drawWedge
414
 
     * @param {Number} x x-coordinate of the wedge's center point
415
 
     * @param {Number} y y-coordinate of the wedge's center point
416
 
     * @param {Number} startAngle starting angle in degrees
417
 
     * @param {Number} arc sweep of the wedge. Negative values draw clockwise.
418
 
     * @param {Number} radius radius of wedge. If [optional] yRadius is defined, then radius is the x radius.
419
 
     * @param {Number} yRadius [optional] y radius for wedge.
420
 
     * @private
421
 
     */
422
 
    drawWedge: function(x, y, startAngle, arc, radius, yRadius)
423
 
    {
424
 
        var segs,
425
 
            segAngle,
426
 
            theta,
427
 
            angle,
428
 
            angleMid,
429
 
            ax,
430
 
            ay,
431
 
            bx,
432
 
            by,
433
 
            cx,
434
 
            cy,
435
 
            i = 0;
436
 
        yRadius = yRadius || radius;
437
 
 
438
 
        this._drawingComplete = false;
439
 
        // move to x,y position
440
 
        this._updateDrawingQueue(["moveTo", x, y]);
441
 
        
442
 
        yRadius = yRadius || radius;
443
 
        
444
 
        // limit sweep to reasonable numbers
445
 
        if(Math.abs(arc) > 360)
446
 
        {
447
 
            arc = 360;
448
 
        }
449
 
        
450
 
        // First we calculate how many segments are needed
451
 
        // for a smooth arc.
452
 
        segs = Math.ceil(Math.abs(arc) / 45);
453
 
        
454
 
        // Now calculate the sweep of each segment.
455
 
        segAngle = arc / segs;
456
 
        
457
 
        // The math requires radians rather than degrees. To convert from degrees
458
 
        // use the formula (degrees/180)*Math.PI to get radians.
459
 
        theta = -(segAngle / 180) * Math.PI;
460
 
        
461
 
        // convert angle startAngle to radians
462
 
        angle = (startAngle / 180) * Math.PI;
463
 
        
464
 
        // draw the curve in segments no larger than 45 degrees.
465
 
        if(segs > 0)
466
 
        {
467
 
            // draw a line from the center to the start of the curve
468
 
            ax = x + Math.cos(startAngle / 180 * Math.PI) * radius;
469
 
            ay = y + Math.sin(startAngle / 180 * Math.PI) * yRadius;
470
 
            this.lineTo(ax, ay);
471
 
            // Loop for drawing curve segments
472
 
            for(; i < segs; ++i)
473
 
            {
474
 
                angle += theta;
475
 
                angleMid = angle - (theta / 2);
476
 
                bx = x + Math.cos(angle) * radius;
477
 
                by = y + Math.sin(angle) * yRadius;
478
 
                cx = x + Math.cos(angleMid) * (radius / Math.cos(theta / 2));
479
 
                cy = y + Math.sin(angleMid) * (yRadius / Math.cos(theta / 2));
480
 
                this._updateDrawingQueue(["quadraticCurveTo", cx, cy, bx, by]);
481
 
            }
482
 
            // close the wedge by drawing a line to the center
483
 
            this._updateDrawingQueue(["lineTo", x, y]);
484
 
        }
485
 
        this._trackSize(0 , 0);
486
 
        this._trackSize(radius * 2, radius * 2);
487
 
        return this;
488
 
    },
489
 
    
490
 
    /**
491
 
     * Completes a drawing operation. 
492
 
     *
493
 
     * @method end
494
 
     */
495
 
    end: function() {
496
 
        this._closePath();
497
 
        return this;
498
 
    },
499
 
 
500
 
    /**
501
 
     * Ends a fill and stroke
502
 
     *
503
 
     * @method closePath
504
 
     */
505
 
    closePath: function()
506
 
    {
507
 
        this._updateDrawingQueue(["closePath"]);
508
 
        this._updateDrawingQueue(["beginPath"]);
509
 
    },
510
 
 
511
 
        /**
512
 
         * Clears the graphics object.
513
 
         *
514
 
         * @method clear
515
 
         */
516
 
    
517
 
    /**
518
 
     * Returns a linear gradient fill
519
 
     *
520
 
     * @method _getLinearGradient
521
 
     * @return CanvasGradient
522
 
     * @private
523
 
     */
524
 
    _getLinearGradient: function() {
525
 
        var isNumber = Y.Lang.isNumber,
526
 
            fill = this.get("fill"),
527
 
            stops = fill.stops,
528
 
            opacity,
529
 
            color,
530
 
            stop,
531
 
            i = 0,
532
 
            len = stops.length,
533
 
            gradient,
534
 
            x = 0,
535
 
            y = 0,
536
 
            w = this.get("width"),
537
 
            h = this.get("height"),
538
 
            r = fill.rotation || 0,
539
 
            x1, x2, y1, y2,
540
 
            cx = x + w/2,
541
 
            cy = y + h/2,
542
 
            offset,
543
 
            radCon = Math.PI/180,
544
 
            tanRadians = parseFloat(parseFloat(Math.tan(r * radCon)).toFixed(8));
545
 
        if(Math.abs(tanRadians) * w/2 >= h/2)
546
 
        {
547
 
            if(r < 180)
548
 
            {
549
 
                y1 = y;
550
 
                y2 = y + h;
551
 
            }
552
 
            else
553
 
            {
554
 
                y1 = y + h;
555
 
                y2 = y;
556
 
            }
557
 
            x1 = cx - ((cy - y1)/tanRadians);
558
 
            x2 = cx - ((cy - y2)/tanRadians); 
559
 
        }
560
 
        else
561
 
        {
562
 
            if(r > 90 && r < 270)
563
 
            {
564
 
                x1 = x + w;
565
 
                x2 = x;
566
 
            }
567
 
            else
568
 
            {
569
 
                x1 = x;
570
 
                x2 = x + w;
571
 
            }
572
 
            y1 = ((tanRadians * (cx - x1)) - cy) * -1;
573
 
            y2 = ((tanRadians * (cx - x2)) - cy) * -1;
574
 
        }
575
 
        gradient = this._context.createLinearGradient(x1, y1, x2, y2);
576
 
        for(; i < len; ++i)
577
 
        {
578
 
            stop = stops[i];
579
 
            opacity = stop.opacity;
580
 
            color = stop.color;
581
 
            offset = stop.offset;
582
 
            if(isNumber(opacity))
583
 
            {
584
 
                opacity = Math.max(0, Math.min(1, opacity));
585
 
                color = this._toRGBA(color, opacity);
586
 
            }
587
 
            else
588
 
            {
589
 
                color = TORGB(color);
590
 
            }
591
 
            offset = stop.offset || i/(len - 1);
592
 
            gradient.addColorStop(offset, color);
593
 
        }
594
 
        return gradient;
595
 
    },
596
 
 
597
 
    /**
598
 
     * Returns a radial gradient fill
599
 
     *
600
 
     * @method _getRadialGradient
601
 
     * @return CanvasGradient
602
 
     * @private
603
 
     */
604
 
    _getRadialGradient: function() {
605
 
        var isNumber = Y.Lang.isNumber,
606
 
            fill = this.get("fill"),
607
 
            r = fill.r,
608
 
            fx = fill.fx,
609
 
            fy = fill.fy,
610
 
            stops = fill.stops,
611
 
            opacity,
612
 
            color,
613
 
            stop,
614
 
            i = 0,
615
 
            len = stops.length,
616
 
            gradient,
617
 
            x = 0,
618
 
            y = 0,
619
 
            w = this.get("width"),
620
 
            h = this.get("height"),
621
 
            x1, x2, y1, y2, r2, 
622
 
            xc, yc, xn, yn, d, 
623
 
            offset,
624
 
            ratio,
625
 
            stopMultiplier;
626
 
        xc = x + w/2;
627
 
        yc = y + h/2;
628
 
        x1 = w * fx;
629
 
        y1 = h * fy;
630
 
        x2 = x + w/2;
631
 
        y2 = y + h/2;
632
 
        r2 = w * r;
633
 
        d = Math.sqrt( Math.pow(Math.abs(xc - x1), 2) + Math.pow(Math.abs(yc - y1), 2) );
634
 
        if(d >= r2)
635
 
        {
636
 
            ratio = d/r2;
637
 
            //hack. gradient won't show if it is exactly on the edge of the arc
638
 
            if(ratio === 1)
639
 
            {
640
 
                ratio = 1.01;
641
 
            }
642
 
            xn = (x1 - xc)/ratio;
643
 
            yn = (y1 - yc)/ratio;
644
 
            xn = xn > 0 ? Math.floor(xn) : Math.ceil(xn);
645
 
            yn = yn > 0 ? Math.floor(yn) : Math.ceil(yn);
646
 
            x1 = xc + xn;
647
 
            y1 = yc + yn;
648
 
        }
649
 
        
650
 
        //If the gradient radius is greater than the circle's, adjusting the radius stretches the gradient properly.
651
 
        //If the gradient radius is less than the circle's, adjusting the radius of the gradient will not work. 
652
 
        //Instead, adjust the color stops to reflect the smaller radius.
653
 
        if(r >= 0.5)
654
 
        {
655
 
            gradient = this._context.createRadialGradient(x1, y1, r, x2, y2, r * w);
656
 
            stopMultiplier = 1;
657
 
        }
658
 
        else
659
 
        {
660
 
            gradient = this._context.createRadialGradient(x1, y1, r, x2, y2, w/2);
661
 
            stopMultiplier = r * 2;
662
 
        }
663
 
        for(; i < len; ++i)
664
 
        {
665
 
            stop = stops[i];
666
 
            opacity = stop.opacity;
667
 
            color = stop.color;
668
 
            offset = stop.offset;
669
 
            if(isNumber(opacity))
670
 
            {
671
 
                opacity = Math.max(0, Math.min(1, opacity));
672
 
                color = this._toRGBA(color, opacity);
673
 
            }
674
 
            else
675
 
            {
676
 
                color = TORGB(color);
677
 
            }
678
 
            offset = stop.offset || i/(len - 1);
679
 
            offset *= stopMultiplier;
680
 
            if(offset <= 1)
681
 
            {
682
 
                gradient.addColorStop(offset, color);
683
 
            }
684
 
        }
685
 
        return gradient;
686
 
    },
687
 
 
688
 
 
689
 
    /**
690
 
     * Clears all values
691
 
     *
692
 
     * @method _initProps
693
 
     * @private
694
 
     */
695
 
    _initProps: function() {
696
 
        this._methods = [];
697
 
        this._lineToMethods = [];
698
 
        this._xcoords = [0];
699
 
                this._ycoords = [0];
700
 
                this._width = 0;
701
 
        this._height = 0;
702
 
        this._left = 0;
703
 
        this._top = 0;
704
 
        this._right = 0;
705
 
        this._bottom = 0;
706
 
    },
707
 
   
708
 
    /**
709
 
     * Indicates a drawing has completed.
710
 
     *
711
 
     * @property _drawingComplete
712
 
     * @type Boolean
713
 
     * @private
714
 
     */
715
 
    _drawingComplete: false,
716
 
 
717
 
    /**
718
 
     * Creates canvas element
719
 
     *
720
 
     * @method _createGraphic
721
 
     * @return HTMLCanvasElement
722
 
     * @private
723
 
     */
724
 
    _createGraphic: function(config) {
725
 
        var graphic = Y.config.doc.createElement('canvas');
726
 
        return graphic;
727
 
    },
728
 
    
729
 
    /**
730
 
     * Updates the size of the graphics object
731
 
     *
732
 
     * @method _trackSize
733
 
     * @param {Number} w width
734
 
     * @param {Number} h height
735
 
     * @private
736
 
     */
737
 
    _trackSize: function(w, h) {
738
 
        if (w > this._right) {
739
 
            this._right = w;
740
 
        }
741
 
        if(w < this._left)
742
 
        {
743
 
            this._left = w;    
744
 
        }
745
 
        if (h < this._top)
746
 
        {
747
 
            this._top = h;
748
 
        }
749
 
        if (h > this._bottom) 
750
 
        {
751
 
            this._bottom = h;
752
 
        }
753
 
        this._width = this._right - this._left;
754
 
        this._height = this._bottom - this._top;
755
 
    }
756
 
};
757
 
Y.CanvasDrawing = CanvasDrawing;
758
 
/**
759
 
 * <a href="http://www.w3.org/TR/html5/the-canvas-element.html">Canvas</a> implementation of the <a href="Shape.html">`Shape`</a> class. 
760
 
 * `CanvasShape` is not intended to be used directly. Instead, use the <a href="Shape.html">`Shape`</a> class. 
761
 
 * If the browser lacks <a href="http://www.w3.org/TR/SVG/">SVG</a> capabilities but has 
762
 
 * <a href="http://www.w3.org/TR/html5/the-canvas-element.html">Canvas</a> capabilities, the <a href="Shape.html">`Shape`</a> 
763
 
 * class will point to the `CanvasShape` class.
764
 
 *
765
 
 * @module graphics
766
 
 * @class CanvasShape
767
 
 * @constructor
768
 
 */
769
 
CanvasShape = function(cfg)
770
 
{
771
 
    this._transforms = [];
772
 
    this.matrix = new Y.Matrix();
773
 
    CanvasShape.superclass.constructor.apply(this, arguments);
774
 
};
775
 
 
776
 
CanvasShape.NAME = "canvasShape";
777
 
 
778
 
Y.extend(CanvasShape, Y.GraphicBase, Y.mix({
779
 
    /**
780
 
     * Init method, invoked during construction.
781
 
     * Calls `initializer` method.
782
 
     *
783
 
     * @method init
784
 
     * @protected
785
 
     */
786
 
    init: function()
787
 
        {
788
 
                this.initializer.apply(this, arguments);
789
 
        },
790
 
 
791
 
        /**
792
 
         * Initializes the shape
793
 
         *
794
 
         * @private
795
 
         * @method _initialize
796
 
         */
797
 
        initializer: function(cfg)
798
 
        {
799
 
                var host = this,
800
 
            graphic = cfg.graphic;
801
 
        host._initProps();
802
 
                host.createNode(); 
803
 
                host._xcoords = [0];
804
 
                host._ycoords = [0];
805
 
        if(graphic)
806
 
        {
807
 
            this._setGraphic(graphic);
808
 
        }
809
 
                host._updateHandler();
810
 
        },
811
 
 
812
 
    /**
813
 
     * Set the Graphic instance for the shape.
814
 
     *
815
 
     * @method _setGraphic
816
 
     * @param {Graphic | Node | HTMLElement | String} render This param is used to determine the graphic instance. If it is a `Graphic` instance, it will be assigned
817
 
     * to the `graphic` attribute. Otherwise, a new Graphic instance will be created and rendered into the dom element that the render represents.
818
 
     * @private
819
 
     */
820
 
    _setGraphic: function(render)
821
 
    {
822
 
        var graphic;
823
 
        if(render instanceof Y.CanvasGraphic)
824
 
        {
825
 
                    this._graphic = render;
826
 
        }
827
 
        else
828
 
        {
829
 
            render = Y.one(render);
830
 
            graphic = new Y.CanvasGraphic({
831
 
                render: render
832
 
            });
833
 
            graphic._appendShape(this);
834
 
            this._graphic = graphic;
835
 
        }
836
 
    },
837
 
   
838
 
        /**
839
 
         * Add a class name to each node.
840
 
         *
841
 
         * @method addClass
842
 
         * @param {String} className the class name to add to the node's class attribute 
843
 
         */
844
 
        addClass: function(className)
845
 
        {
846
 
                var node = Y.one(this.get("node"));
847
 
                node.addClass(className);
848
 
        },
849
 
        
850
 
        /**
851
 
         * Removes a class name from each node.
852
 
         *
853
 
         * @method removeClass
854
 
         * @param {String} className the class name to remove from the node's class attribute
855
 
         */
856
 
        removeClass: function(className)
857
 
        {
858
 
                var node = Y.one(this.get("node"));
859
 
                node.removeClass(className);
860
 
        },
861
 
 
862
 
        /**
863
 
         * Gets the current position of the node in page coordinates.
864
 
         *
865
 
         * @method getXY
866
 
         * @return Array The XY position of the shape.
867
 
         */
868
 
        getXY: function()
869
 
        {
870
 
                var graphic = this.get("graphic"),
871
 
                        parentXY = graphic.getXY(),
872
 
                        x = this.get("x"),
873
 
                        y = this.get("y");
874
 
                return [parentXY[0] + x, parentXY[1] + y];
875
 
        },
876
 
 
877
 
        /**
878
 
         * Set the position of the shape in page coordinates, regardless of how the node is positioned.
879
 
         *
880
 
         * @method setXY
881
 
         * @param {Array} Contains X & Y values for new position (coordinates are page-based)
882
 
         */
883
 
        setXY: function(xy)
884
 
        {
885
 
                var graphic = this.get("graphic"),
886
 
                        parentXY = graphic.getXY(),
887
 
                        x = xy[0] - parentXY[0],
888
 
                        y = xy[1] - parentXY[1];
889
 
                this._set("x", x);
890
 
                this._set("y", y);
891
 
                this._updateNodePosition(x, y);
892
 
        },
893
 
 
894
 
        /**
895
 
         * Determines whether the node is an ancestor of another HTML element in the DOM hierarchy. 
896
 
         *
897
 
         * @method contains
898
 
         * @param {CanvasShape | HTMLElement} needle The possible node or descendent
899
 
         * @return Boolean Whether or not this shape is the needle or its ancestor.
900
 
         */
901
 
        contains: function(needle)
902
 
        {
903
 
                return needle === Y.one(this.node);
904
 
        },
905
 
 
906
 
        /**
907
 
         * Test if the supplied node matches the supplied selector.
908
 
         *
909
 
         * @method test
910
 
         * @param {String} selector The CSS selector to test against.
911
 
         * @return Boolean Wheter or not the shape matches the selector.
912
 
         */
913
 
        test: function(selector)
914
 
        {
915
 
                return Y.one(this.get("node")).test(selector);
916
 
                //return Y.Selector.test(this.node, selector);
917
 
        },
918
 
 
919
 
        /**
920
 
         * Compares nodes to determine if they match.
921
 
         * Node instances can be compared to each other and/or HTMLElements.
922
 
         * @method compareTo
923
 
         * @param {HTMLElement | Node} refNode The reference node to compare to the node.
924
 
         * @return {Boolean} True if the nodes match, false if they do not.
925
 
         */
926
 
        compareTo: function(refNode) {
927
 
                var node = this.node;
928
 
                return node === refNode;
929
 
        },
930
 
 
931
 
        /**
932
 
         * Value function for fill attribute
933
 
         *
934
 
         * @method _getDefaultFill
935
 
         * @return Object
936
 
         * @private
937
 
         */
938
 
        _getDefaultFill: function() {
939
 
                return {
940
 
                        type: "solid",
941
 
                        cx: 0.5,
942
 
                        cy: 0.5,
943
 
                        fx: 0.5,
944
 
                        fy: 0.5,
945
 
                        r: 0.5
946
 
                };
947
 
        },
948
 
 
949
 
        /**
950
 
         * Value function for stroke attribute
951
 
         *
952
 
         * @method _getDefaultStroke
953
 
         * @return Object
954
 
         * @private
955
 
         */
956
 
        _getDefaultStroke: function() 
957
 
        {
958
 
                return {
959
 
                        weight: 1,
960
 
                        dashstyle: "none",
961
 
                        color: "#000",
962
 
                        opacity: 1.0
963
 
                };
964
 
        },
965
 
 
966
 
        /**
967
 
         * Left edge of the path
968
 
         *
969
 
     * @property _left
970
 
     * @type Number
971
 
         * @private
972
 
         */
973
 
        _left: 0,
974
 
 
975
 
        /**
976
 
         * Right edge of the path
977
 
         *
978
 
     * @property _right
979
 
     * @type Number
980
 
         * @private
981
 
         */
982
 
        _right: 0,
983
 
        
984
 
        /**
985
 
         * Top edge of the path
986
 
         *
987
 
     * @property _top
988
 
     * @type Number
989
 
         * @private
990
 
         */
991
 
        _top: 0, 
992
 
        
993
 
        /**
994
 
         * Bottom edge of the path
995
 
         *
996
 
     * @property _bottom
997
 
     * @type Number
998
 
         * @private
999
 
         */
1000
 
        _bottom: 0,
1001
 
 
1002
 
        /**
1003
 
         * Creates the dom node for the shape.
1004
 
         *
1005
 
     * @method createNode
1006
 
         * @return HTMLElement
1007
 
         * @private
1008
 
         */
1009
 
        createNode: function()
1010
 
        {
1011
 
                var node = Y.config.doc.createElement('canvas'),
1012
 
                        id = this.get("id");
1013
 
                this._context = node.getContext('2d');
1014
 
                node.setAttribute("overflow", "visible");
1015
 
        node.style.overflow = "visible";
1016
 
        if(!this.get("visible"))
1017
 
        {
1018
 
            node.style.visibility = "hidden";
1019
 
        }
1020
 
                node.setAttribute("id", id);
1021
 
                id = "#" + id;
1022
 
                this.node = node;
1023
 
                this.addClass("yui3-" + SHAPE + " yui3-" + this.name);
1024
 
        },
1025
 
        
1026
 
        /**
1027
 
     * Overrides default `on` method. Checks to see if its a dom interaction event. If so, 
1028
 
     * return an event attached to the `node` element. If not, return the normal functionality.
1029
 
     *
1030
 
     * @method on
1031
 
     * @param {String} type event type
1032
 
     * @param {Object} callback function
1033
 
         * @private
1034
 
         */
1035
 
        on: function(type, fn)
1036
 
        {
1037
 
                if(Y.Node.DOM_EVENTS[type])
1038
 
                {
1039
 
                        return Y.one("#" +  this.get("id")).on(type, fn);
1040
 
                }
1041
 
                return Y.on.apply(this, arguments);
1042
 
        },
1043
 
        
1044
 
        /**
1045
 
         * Adds a stroke to the shape node.
1046
 
         *
1047
 
         * @method _strokeChangeHandler
1048
 
     * @param {Object} stroke Properties of the `stroke` attribute.
1049
 
         * @private
1050
 
         */
1051
 
        _setStrokeProps: function(stroke)
1052
 
        {
1053
 
                var color = stroke.color,
1054
 
                        weight = PARSE_FLOAT(stroke.weight),
1055
 
                        opacity = PARSE_FLOAT(stroke.opacity),
1056
 
                        linejoin = stroke.linejoin || "round",
1057
 
                        linecap = stroke.linecap || "butt",
1058
 
                        dashstyle = stroke.dashstyle;
1059
 
                this._miterlimit = null;
1060
 
                this._dashstyle = (dashstyle && Y.Lang.isArray(dashstyle) && dashstyle.length > 1) ? dashstyle : null;
1061
 
                this._strokeWeight = weight;
1062
 
 
1063
 
                if (IS_NUMBER(weight) && weight > 0) 
1064
 
                {
1065
 
                        this._stroke = 1;
1066
 
                } 
1067
 
                else 
1068
 
                {
1069
 
                        this._stroke = 0;
1070
 
                }
1071
 
                if (IS_NUMBER(opacity)) {
1072
 
                        this._strokeStyle = this._toRGBA(color, opacity);
1073
 
                }
1074
 
                else
1075
 
                {
1076
 
                        this._strokeStyle = color;
1077
 
                }
1078
 
                this._linecap = linecap;
1079
 
                if(linejoin == "round" || linejoin == "square")
1080
 
                {
1081
 
                        this._linejoin = linejoin;
1082
 
                }
1083
 
                else
1084
 
                {
1085
 
                        linejoin = parseInt(linejoin, 10);
1086
 
                        if(IS_NUMBER(linejoin))
1087
 
                        {
1088
 
                                this._miterlimit =  Math.max(linejoin, 1);
1089
 
                                this._linejoin = "miter";
1090
 
                        }
1091
 
                }
1092
 
        },
1093
 
 
1094
 
    /**
1095
 
     * Sets the value of an attribute.
1096
 
     *
1097
 
     * @method set
1098
 
     * @param {String|Object} name The name of the attribute. Alternatively, an object of key value pairs can 
1099
 
     * be passed in to set multiple attributes at once.
1100
 
     * @param {Any} value The value to set the attribute to. This value is ignored if an object is received as 
1101
 
     * the name param.
1102
 
     */
1103
 
        set: function() 
1104
 
        {
1105
 
                var host = this,
1106
 
                        val = arguments[0];
1107
 
                AttributeLite.prototype.set.apply(host, arguments);
1108
 
                if(host.initialized)
1109
 
                {
1110
 
                        host._updateHandler();
1111
 
                }
1112
 
        },
1113
 
        
1114
 
        /**
1115
 
         * Adds a fill to the shape node.
1116
 
         *
1117
 
         * @method _setFillProps 
1118
 
     * @param {Object} fill Properties of the `fill` attribute.
1119
 
         * @private
1120
 
         */
1121
 
        _setFillProps: function(fill)
1122
 
        {
1123
 
                var isNumber = IS_NUMBER,
1124
 
                        color = fill.color,
1125
 
                        opacity,
1126
 
                        type = fill.type;
1127
 
                if(type == "linear" || type == "radial")
1128
 
                {
1129
 
                        this._fillType = type;
1130
 
                }
1131
 
                else if(color)
1132
 
                {
1133
 
                        opacity = fill.opacity;
1134
 
                        if (isNumber(opacity)) 
1135
 
                        {
1136
 
                                opacity = Math.max(0, Math.min(1, opacity));
1137
 
                                color = this._toRGBA(color, opacity);
1138
 
                        } 
1139
 
                        else 
1140
 
                        {
1141
 
                                color = TORGB(color);
1142
 
                        }
1143
 
 
1144
 
                        this._fillColor = color;
1145
 
                        this._fillType = 'solid';
1146
 
                }
1147
 
                else
1148
 
                {
1149
 
                        this._fillColor = null;
1150
 
                }
1151
 
        },
1152
 
 
1153
 
        /**
1154
 
         * Specifies a 2d translation.
1155
 
         *
1156
 
         * @method translate
1157
 
         * @param {Number} x The value to transate on the x-axis.
1158
 
         * @param {Number} y The value to translate on the y-axis.
1159
 
         */
1160
 
        translate: function(x, y)
1161
 
        {
1162
 
                this._translateX += x;
1163
 
                this._translateY += y;
1164
 
                this._addTransform("translate", arguments);
1165
 
        },
1166
 
 
1167
 
        /**
1168
 
         * Translates the shape along the x-axis. When translating x and y coordinates,
1169
 
         * use the `translate` method.
1170
 
         *
1171
 
         * @method translateX
1172
 
         * @param {Number} x The value to translate.
1173
 
         */
1174
 
        translateX: function(x)
1175
 
    {
1176
 
        this._translateX += x;
1177
 
        this._addTransform("translateX", arguments);
1178
 
    },
1179
 
 
1180
 
        /**
1181
 
         * Performs a translate on the y-coordinate. When translating x and y coordinates,
1182
 
         * use the `translate` method.
1183
 
         *
1184
 
         * @method translateY
1185
 
         * @param {Number} y The value to translate.
1186
 
         */
1187
 
        translateY: function(y)
1188
 
    {
1189
 
        this._translateY += y;
1190
 
        this._addTransform("translateY", arguments);
1191
 
    },
1192
 
 
1193
 
    /**
1194
 
     * Skews the shape around the x-axis and y-axis.
1195
 
     *
1196
 
     * @method skew
1197
 
     * @param {Number} x The value to skew on the x-axis.
1198
 
     * @param {Number} y The value to skew on the y-axis.
1199
 
     */
1200
 
    skew: function(x, y)
1201
 
    {
1202
 
        this._addTransform("skew", arguments);
1203
 
    },
1204
 
 
1205
 
        /**
1206
 
         * Skews the shape around the x-axis.
1207
 
         *
1208
 
         * @method skewX
1209
 
         * @param {Number} x x-coordinate
1210
 
         */
1211
 
         skewX: function(x)
1212
 
         {
1213
 
                this._addTransform("skewX", arguments);
1214
 
         },
1215
 
 
1216
 
        /**
1217
 
         * Skews the shape around the y-axis.
1218
 
         *
1219
 
         * @method skewY
1220
 
         * @param {Number} y y-coordinate
1221
 
         */
1222
 
         skewY: function(y)
1223
 
         {
1224
 
                this._addTransform("skewY", arguments);
1225
 
         },
1226
 
 
1227
 
        /**
1228
 
         * Rotates the shape clockwise around it transformOrigin.
1229
 
         *
1230
 
         * @method rotate
1231
 
         * @param {Number} deg The degree of the rotation.
1232
 
         */
1233
 
         rotate: function(deg)
1234
 
         {
1235
 
                this._rotation = deg;
1236
 
                this._addTransform("rotate", arguments);
1237
 
         },
1238
 
 
1239
 
        /**
1240
 
         * Specifies a 2d scaling operation.
1241
 
         *
1242
 
         * @method scale
1243
 
         * @param {Number} val
1244
 
         */
1245
 
        scale: function(x, y)
1246
 
        {
1247
 
                this._addTransform("scale", arguments);
1248
 
        },
1249
 
        
1250
 
    /**
1251
 
     * Storage for `rotation` atribute.
1252
 
     *
1253
 
     * @property _rotation
1254
 
     * @type Number
1255
 
         * @private
1256
 
         */
1257
 
        _rotation: 0,
1258
 
    
1259
 
    /**
1260
 
     * Storage for the transform attribute.
1261
 
     *
1262
 
     * @property _transform
1263
 
     * @type String
1264
 
     * @private
1265
 
     */
1266
 
    _transform: "",
1267
 
 
1268
 
    /**
1269
 
     * Adds a transform to the shape.
1270
 
     *
1271
 
     * @method _addTransform
1272
 
     * @param {String} type The transform being applied.
1273
 
     * @param {Array} args The arguments for the transform.
1274
 
         * @private
1275
 
         */
1276
 
        _addTransform: function(type, args)
1277
 
        {
1278
 
        args = Y.Array(args);
1279
 
        this._transform = Y_LANG.trim(this._transform + " " + type + "(" + args.join(", ") + ")");
1280
 
        args.unshift(type);
1281
 
        this._transforms.push(args);
1282
 
        if(this.initialized)
1283
 
        {
1284
 
            this._updateTransform();
1285
 
        }
1286
 
        },
1287
 
 
1288
 
        /**
1289
 
     * Applies all transforms.
1290
 
     *
1291
 
     * @method _updateTransform
1292
 
         * @private
1293
 
         */
1294
 
        _updateTransform: function()
1295
 
        {
1296
 
                var node = this.node,
1297
 
                        key,
1298
 
                        transform,
1299
 
                        transformOrigin = this.get("transformOrigin"),
1300
 
            matrix = this.matrix,
1301
 
            i = 0,
1302
 
            len = this._transforms.length;
1303
 
        
1304
 
        if(this._transforms && this._transforms.length > 0)
1305
 
        {
1306
 
            for(; i < len; ++i)
1307
 
            {
1308
 
                key = this._transforms[i].shift();
1309
 
                if(key)
1310
 
                {
1311
 
                    matrix[key].apply(matrix, this._transforms[i]); 
1312
 
                }
1313
 
            }
1314
 
            transform = matrix.toCSSText();
1315
 
        }
1316
 
        
1317
 
        this._graphic.addToRedrawQueue(this);    
1318
 
                transformOrigin = (100 * transformOrigin[0]) + "% " + (100 * transformOrigin[1]) + "%";
1319
 
                node.style.MozTransformOrigin = transformOrigin; 
1320
 
                node.style.webkitTransformOrigin = transformOrigin;
1321
 
                node.style.msTransformOrigin = transformOrigin;
1322
 
                node.style.OTransformOrigin = transformOrigin;
1323
 
        if(transform)
1324
 
                {
1325
 
            node.style.MozTransform = transform;
1326
 
            node.style.webkitTransform = transform;
1327
 
            node.style.msTransform = transform;
1328
 
            node.style.OTransform = transform;
1329
 
                }
1330
 
        this._transforms = [];
1331
 
        },
1332
 
 
1333
 
        /**
1334
 
     * Updates `Shape` based on attribute changes.
1335
 
     *
1336
 
     * @method _updateHandler
1337
 
         * @private
1338
 
         */
1339
 
        _updateHandler: function()
1340
 
        {
1341
 
                this._draw();
1342
 
                this._updateTransform();
1343
 
        },
1344
 
        
1345
 
        /**
1346
 
         * Updates the shape.
1347
 
         *
1348
 
         * @method _draw
1349
 
         * @private
1350
 
         */
1351
 
        _draw: function()
1352
 
        {
1353
 
        var node = this.node;
1354
 
        this.clear();
1355
 
                this._closePath();
1356
 
                node.style.left = this.get("x") + "px";
1357
 
                node.style.top = this.get("y") + "px";
1358
 
        },
1359
 
 
1360
 
        /**
1361
 
         * Completes a shape or drawing
1362
 
         *
1363
 
         * @method _closePath
1364
 
         * @private
1365
 
         */
1366
 
        _closePath: function()
1367
 
        {
1368
 
                if(!this._methods)
1369
 
                {
1370
 
                        return;
1371
 
                }
1372
 
                var node = this.get("node"),
1373
 
                        w = this._right - this._left,
1374
 
                        h = this._bottom - this._top,
1375
 
                        context = this._context,
1376
 
                        methods = [],
1377
 
                        cachedMethods = this._methods.concat(),
1378
 
                        i = 0,
1379
 
                        j,
1380
 
                        method,
1381
 
                        args,
1382
 
            argsLen,
1383
 
                        len = 0;
1384
 
                this._context.clearRect(0, 0, node.width, node.height);
1385
 
           if(this._methods)
1386
 
           {
1387
 
                        len = cachedMethods.length;
1388
 
                        if(!len || len < 1)
1389
 
                        {
1390
 
                                return;
1391
 
                        }
1392
 
                        for(; i < len; ++i)
1393
 
                        {
1394
 
                                methods[i] = cachedMethods[i].concat();
1395
 
                                args = methods[i];
1396
 
                argsLen = args[0] == "quadraticCurveTo" ? args.length : 3;
1397
 
                                for(j = 1; j < argsLen; ++j)
1398
 
                                {
1399
 
                                        if(j % 2 === 0)
1400
 
                                        {
1401
 
                                                args[j] = args[j] - this._top;
1402
 
                                        }
1403
 
                                        else
1404
 
                                        {
1405
 
                                                args[j] = args[j] - this._left;
1406
 
                                        }
1407
 
                                }
1408
 
                        }
1409
 
            node.setAttribute("width", Math.min(w, 2000));
1410
 
            node.setAttribute("height", Math.min(2000, h));
1411
 
            context.beginPath();
1412
 
                        for(i = 0; i < len; ++i)
1413
 
                        {
1414
 
                                args = methods[i].concat();
1415
 
                                if(args && args.length > 0)
1416
 
                                {
1417
 
                                        method = args.shift();
1418
 
                                        if(method)
1419
 
                                        {
1420
 
                        if(method == "closePath")
1421
 
                        {
1422
 
                            this._strokeAndFill(context);
1423
 
                        }
1424
 
                                                if(method && method == "lineTo" && this._dashstyle)
1425
 
                                                {
1426
 
                                                        args.unshift(this._xcoords[i] - this._left, this._ycoords[i] - this._top);
1427
 
                                                        this._drawDashedLine.apply(this, args);
1428
 
                                                }
1429
 
                                                else
1430
 
                                                {
1431
 
                            context[method].apply(context, args); 
1432
 
                                                }
1433
 
                                        }
1434
 
                                }
1435
 
                        }
1436
 
 
1437
 
            this._strokeAndFill(context);
1438
 
                        this._drawingComplete = true;
1439
 
                        this._clearAndUpdateCoords();
1440
 
                        this._updateNodePosition();
1441
 
                        this._methods = cachedMethods;
1442
 
                }
1443
 
        },
1444
 
 
1445
 
    /**
1446
 
     * Completes a stroke and/or fill operation on the context.
1447
 
     *
1448
 
     * @method _strokeAndFill
1449
 
     * @param {Context} Reference to the context element of the canvas instance.
1450
 
     * @private
1451
 
     */
1452
 
    _strokeAndFill: function(context)
1453
 
    {
1454
 
        if (this._fillType) 
1455
 
        {
1456
 
            if(this._fillType == "linear")
1457
 
            {
1458
 
                context.fillStyle = this._getLinearGradient();
1459
 
            }
1460
 
            else if(this._fillType == "radial")
1461
 
            {
1462
 
                context.fillStyle = this._getRadialGradient();
1463
 
            }
1464
 
            else
1465
 
            {
1466
 
                context.fillStyle = this._fillColor;
1467
 
            }
1468
 
            context.closePath();
1469
 
            context.fill();
1470
 
        }
1471
 
 
1472
 
        if (this._stroke) {
1473
 
            if(this._strokeWeight)
1474
 
            {
1475
 
                context.lineWidth = this._strokeWeight;
1476
 
            }
1477
 
            context.lineCap = this._linecap;
1478
 
            context.lineJoin = this._linejoin;
1479
 
            if(this._miterlimit)
1480
 
            {
1481
 
                context.miterLimit = this._miterlimit;
1482
 
            }
1483
 
            context.strokeStyle = this._strokeStyle;
1484
 
            context.stroke();
1485
 
        }
1486
 
    },
1487
 
 
1488
 
        /**
1489
 
         * Draws a dashed line between two points.
1490
 
         * 
1491
 
         * @method _drawDashedLine
1492
 
         * @param {Number} xStart       The x position of the start of the line
1493
 
         * @param {Number} yStart       The y position of the start of the line
1494
 
         * @param {Number} xEnd         The x position of the end of the line
1495
 
         * @param {Number} yEnd         The y position of the end of the line
1496
 
         * @private
1497
 
         */
1498
 
        _drawDashedLine: function(xStart, yStart, xEnd, yEnd)
1499
 
        {
1500
 
                var context = this._context,
1501
 
                        dashsize = this._dashstyle[0],
1502
 
                        gapsize = this._dashstyle[1],
1503
 
                        segmentLength = dashsize + gapsize,
1504
 
                        xDelta = xEnd - xStart,
1505
 
                        yDelta = yEnd - yStart,
1506
 
                        delta = Math.sqrt(Math.pow(xDelta, 2) + Math.pow(yDelta, 2)),
1507
 
                        segmentCount = Math.floor(Math.abs(delta / segmentLength)),
1508
 
                        radians = Math.atan2(yDelta, xDelta),
1509
 
                        xCurrent = xStart,
1510
 
                        yCurrent = yStart,
1511
 
                        i;
1512
 
                xDelta = Math.cos(radians) * segmentLength;
1513
 
                yDelta = Math.sin(radians) * segmentLength;
1514
 
                
1515
 
                for(i = 0; i < segmentCount; ++i)
1516
 
                {
1517
 
                        context.moveTo(xCurrent, yCurrent);
1518
 
                        context.lineTo(xCurrent + Math.cos(radians) * dashsize, yCurrent + Math.sin(radians) * dashsize);
1519
 
                        xCurrent += xDelta;
1520
 
                        yCurrent += yDelta;
1521
 
                }
1522
 
                
1523
 
                context.moveTo(xCurrent, yCurrent);
1524
 
                delta = Math.sqrt((xEnd - xCurrent) * (xEnd - xCurrent) + (yEnd - yCurrent) * (yEnd - yCurrent));
1525
 
                
1526
 
                if(delta > dashsize)
1527
 
                {
1528
 
                        context.lineTo(xCurrent + Math.cos(radians) * dashsize, yCurrent + Math.sin(radians) * dashsize);
1529
 
                }
1530
 
                else if(delta > 0)
1531
 
                {
1532
 
                        context.lineTo(xCurrent + Math.cos(radians) * delta, yCurrent + Math.sin(radians) * delta);
1533
 
                }
1534
 
                
1535
 
                context.moveTo(xEnd, yEnd);
1536
 
        },
1537
 
 
1538
 
        //This should move to CanvasDrawing class. 
1539
 
    //Currently docmented in CanvasDrawing class.
1540
 
    clear: function() {
1541
 
                this._initProps();
1542
 
        if(this.node) 
1543
 
        {
1544
 
            this._context.clearRect(0, 0, this.node.width, this.node.height);
1545
 
        }
1546
 
        return this;
1547
 
        },
1548
 
        
1549
 
        /**
1550
 
         * Returns the bounds for a shape.
1551
 
         *
1552
 
     * Calculates the a new bounding box from the original corner coordinates (base on size and position) and the transform matrix.
1553
 
     * The calculated bounding box is used by the graphic instance to calculate its viewBox. 
1554
 
     *
1555
 
         * @method getBounds
1556
 
         * @return Object
1557
 
         */
1558
 
        getBounds: function()
1559
 
        {
1560
 
                var stroke = this.get("stroke"),
1561
 
                        w = this.get("width"),
1562
 
                        h = this.get("height"),
1563
 
                        x = this.get("x"),
1564
 
                        y = this.get("y"),
1565
 
            wt = 0;
1566
 
                if(stroke && stroke.weight)
1567
 
                {
1568
 
                        wt = stroke.weight;
1569
 
                }
1570
 
        w = (x + w + wt) - (x - wt); 
1571
 
        h = (y + h + wt) - (y - wt);
1572
 
        x -= wt;
1573
 
        y -= wt;
1574
 
                return this.matrix.getContentRect(w, h, x, y);
1575
 
        },
1576
 
 
1577
 
    /**
1578
 
     * Destroys the shape instance.
1579
 
     *
1580
 
     * @method destroy
1581
 
     */
1582
 
    destroy: function()
1583
 
    {
1584
 
        var graphic = this.get("graphic");
1585
 
        if(graphic)
1586
 
        {
1587
 
            graphic.removeShape(this);
1588
 
        }
1589
 
        else
1590
 
        {
1591
 
            this._destroy();
1592
 
        }
1593
 
    },
1594
 
 
1595
 
    /**
1596
 
     *  Implementation for shape destruction
1597
 
     *
1598
 
     *  @method destroy
1599
 
     *  @protected
1600
 
     */
1601
 
    _destroy: function()
1602
 
    {
1603
 
        if(this.node)
1604
 
        {
1605
 
            Y.one(this.node).remove(true);
1606
 
            this._context = null;
1607
 
            this.node = null;
1608
 
        }
1609
 
    }
1610
 
}, Y.CanvasDrawing.prototype));
1611
 
 
1612
 
CanvasShape.ATTRS =  {
1613
 
        /**
1614
 
         * An array of x, y values which indicates the transformOrigin in which to rotate the shape. Valid values range between 0 and 1 representing a 
1615
 
         * fraction of the shape's corresponding bounding box dimension. The default value is [0.5, 0.5].
1616
 
         *
1617
 
         * @config transformOrigin
1618
 
         * @type Array
1619
 
         */
1620
 
        transformOrigin: {
1621
 
                valueFn: function()
1622
 
                {
1623
 
                        return [0.5, 0.5];
1624
 
                }
1625
 
        },
1626
 
        
1627
 
    /**
1628
 
     * <p>A string containing, in order, transform operations applied to the shape instance. The `transform` string can contain the following values:
1629
 
     *     
1630
 
     *    <dl>
1631
 
     *        <dt>rotate</dt><dd>Rotates the shape clockwise around it transformOrigin.</dd>
1632
 
     *        <dt>translate</dt><dd>Specifies a 2d translation.</dd>
1633
 
     *        <dt>skew</dt><dd>Skews the shape around the x-axis and y-axis.</dd>
1634
 
     *        <dt>scale</dt><dd>Specifies a 2d scaling operation.</dd>
1635
 
     *        <dt>translateX</dt><dd>Translates the shape along the x-axis.</dd>
1636
 
     *        <dt>translateY</dt><dd>Translates the shape along the y-axis.</dd>
1637
 
     *        <dt>skewX</dt><dd>Skews the shape around the x-axis.</dd>
1638
 
     *        <dt>skewY</dt><dd>Skews the shape around the y-axis.</dd>
1639
 
     *        <dt>matrix</dt><dd>Specifies a 2D transformation matrix comprised of the specified six values.</dd>      
1640
 
     *    </dl>
1641
 
     * </p>
1642
 
     * <p>Applying transforms through the transform attribute will reset the transform matrix and apply a new transform. The shape class also contains corresponding methods for each transform
1643
 
     * that will apply the transform to the current matrix. The below code illustrates how you might use the `transform` attribute to instantiate a recangle with a rotation of 45 degrees.</p>
1644
 
            var myRect = new Y.Rect({
1645
 
                type:"rect",
1646
 
                width: 50,
1647
 
                height: 40,
1648
 
                transform: "rotate(45)"
1649
 
            };
1650
 
     * <p>The code below would apply `translate` and `rotate` to an existing shape.</p>
1651
 
    
1652
 
        myRect.set("transform", "translate(40, 50) rotate(45)");
1653
 
         * @config transform
1654
 
     * @type String  
1655
 
         */
1656
 
        transform: {
1657
 
                setter: function(val)
1658
 
                {
1659
 
            this.matrix.init(); 
1660
 
                    this._transforms = this.matrix.getTransformArray(val);
1661
 
            this._transform = val;
1662
 
            return val;
1663
 
                },
1664
 
 
1665
 
        getter: function()
1666
 
        {
1667
 
            return this._transform;
1668
 
        }
1669
 
        },
1670
 
 
1671
 
        /**
1672
 
         * Dom node for the shape
1673
 
         *
1674
 
         * @config node
1675
 
         * @type HTMLElement
1676
 
         * @readOnly
1677
 
         */
1678
 
        node: {
1679
 
                readOnly: true,
1680
 
 
1681
 
                getter: function()
1682
 
                {
1683
 
                        return this.node;
1684
 
                }
1685
 
        },
1686
 
 
1687
 
        /**
1688
 
         * Unique id for class instance.
1689
 
         *
1690
 
         * @config id
1691
 
         * @type String
1692
 
         */
1693
 
        id: {
1694
 
                valueFn: function()
1695
 
                {
1696
 
                        return Y.guid();
1697
 
                },
1698
 
 
1699
 
                setter: function(val)
1700
 
                {
1701
 
                        var node = this.node;
1702
 
                        if(node)
1703
 
                        {
1704
 
                                node.setAttribute("id", val);
1705
 
                        }
1706
 
                        return val;
1707
 
                }
1708
 
        },
1709
 
 
1710
 
        /**
1711
 
         * Indicates the width of the shape
1712
 
         *
1713
 
         * @config width
1714
 
         * @type Number
1715
 
         */
1716
 
        width: {
1717
 
        value: 0
1718
 
    },
1719
 
 
1720
 
        /**
1721
 
         * Indicates the height of the shape
1722
 
         *
1723
 
         * @config height
1724
 
         * @type Number
1725
 
         */
1726
 
        height: {
1727
 
        value: 0
1728
 
    },
1729
 
 
1730
 
        /**
1731
 
         * Indicates the x position of shape.
1732
 
         *
1733
 
         * @config x
1734
 
         * @type Number
1735
 
         */
1736
 
        x: {
1737
 
                value: 0
1738
 
        },
1739
 
 
1740
 
        /**
1741
 
         * Indicates the y position of shape.
1742
 
         *
1743
 
         * @config y
1744
 
         * @type Number
1745
 
         */
1746
 
        y: {
1747
 
                value: 0
1748
 
        },
1749
 
 
1750
 
        /**
1751
 
         * Indicates whether the shape is visible.
1752
 
         *
1753
 
         * @config visible
1754
 
         * @type Boolean
1755
 
         */
1756
 
        visible: {
1757
 
                value: true,
1758
 
 
1759
 
                setter: function(val){
1760
 
                        var node = this.get("node"),
1761
 
                visibility = val ? "visible" : "hidden";
1762
 
                        if(node)
1763
 
            {
1764
 
                node.style.visibility = visibility;
1765
 
            }
1766
 
                        return val;
1767
 
                }
1768
 
        },
1769
 
 
1770
 
        /**
1771
 
         * Contains information about the fill of the shape. 
1772
 
     *  <dl>
1773
 
     *      <dt>color</dt><dd>The color of the fill.</dd>
1774
 
     *      <dt>opacity</dt><dd>Number between 0 and 1 that indicates the opacity of the fill. The default value is 1.</dd>
1775
 
     *      <dt>type</dt><dd>Type of fill.
1776
 
     *          <dl>
1777
 
     *              <dt>solid</dt><dd>Solid single color fill. (default)</dd>
1778
 
     *              <dt>linear</dt><dd>Linear gradient fill.</dd>
1779
 
     *              <dt>radial</dt><dd>Radial gradient fill.</dd>
1780
 
     *          </dl>
1781
 
     *      </dd>
1782
 
     *  </dl>
1783
 
     *  <p>If a `linear` or `radial` is specified as the fill type. The following additional property is used:
1784
 
     *  <dl>
1785
 
     *      <dt>stops</dt><dd>An array of objects containing the following properties:
1786
 
     *          <dl>
1787
 
     *              <dt>color</dt><dd>The color of the stop.</dd>
1788
 
     *              <dt>opacity</dt><dd>Number between 0 and 1 that indicates the opacity of the stop. The default value is 1. Note: No effect for IE 6 - 8</dd>
1789
 
     *              <dt>offset</dt><dd>Number between 0 and 1 indicating where the color stop is positioned.</dd> 
1790
 
     *          </dl>
1791
 
     *      </dd>
1792
 
     *      <p>Linear gradients also have the following property:</p>
1793
 
     *      <dt>rotation</dt><dd>Linear gradients flow left to right by default. The rotation property allows you to change the flow by rotation. (e.g. A rotation of 180 would make the gradient pain from right to left.)</dd>
1794
 
     *      <p>Radial gradients have the following additional properties:</p>
1795
 
     *      <dt>r</dt><dd>Radius of the gradient circle.</dd>
1796
 
     *      <dt>fx</dt><dd>Focal point x-coordinate of the gradient.</dd>
1797
 
     *      <dt>fy</dt><dd>Focal point y-coordinate of the gradient.</dd>
1798
 
     *  </dl>
1799
 
     *  <p>The corresponding `SVGShape` class implements the following additional properties.</p>
1800
 
     *  <dl>
1801
 
     *      <dt>cx</dt><dd>
1802
 
     *          <p>The x-coordinate of the center of the gradient circle. Determines where the color stop begins. The default value 0.5.</p>
1803
 
     *      </dd>
1804
 
     *      <dt>cy</dt><dd>
1805
 
     *          <p>The y-coordinate of the center of the gradient circle. Determines where the color stop begins. The default value 0.5.</p>
1806
 
     *      </dd>
1807
 
     *  </dl>
1808
 
     *  <p>These properties are not currently implemented in `CanvasShape` or `VMLShape`.</p> 
1809
 
         *
1810
 
         * @config fill
1811
 
         * @type Object 
1812
 
         */
1813
 
        fill: {
1814
 
                valueFn: "_getDefaultFill",
1815
 
                
1816
 
                setter: function(val)
1817
 
                {
1818
 
                        var fill,
1819
 
                                tmpl = this.get("fill") || this._getDefaultFill();
1820
 
                        fill = (val) ? Y.merge(tmpl, val) : null;
1821
 
                        if(fill && fill.color)
1822
 
                        {
1823
 
                                if(fill.color === undefined || fill.color == "none")
1824
 
                                {
1825
 
                                        fill.color = null;
1826
 
                                }
1827
 
                        }
1828
 
                        this._setFillProps(fill);
1829
 
                        return fill;
1830
 
                }
1831
 
        },
1832
 
 
1833
 
        /**
1834
 
         * Contains information about the stroke of the shape.
1835
 
     *  <dl>
1836
 
     *      <dt>color</dt><dd>The color of the stroke.</dd>
1837
 
     *      <dt>weight</dt><dd>Number that indicates the width of the stroke.</dd>
1838
 
     *      <dt>opacity</dt><dd>Number between 0 and 1 that indicates the opacity of the stroke. The default value is 1.</dd>
1839
 
     *      <dt>dashstyle</dt>Indicates whether to draw a dashed stroke. When set to "none", a solid stroke is drawn. When set to an array, the first index indicates the
1840
 
     *  length of the dash. The second index indicates the length of gap.
1841
 
     *      <dt>linecap</dt><dd>Specifies the linecap for the stroke. The following values can be specified:
1842
 
     *          <dl>
1843
 
     *              <dt>butt (default)</dt><dd>Specifies a butt linecap.</dd>
1844
 
     *              <dt>square</dt><dd>Specifies a sqare linecap.</dd>
1845
 
     *              <dt>round</dt><dd>Specifies a round linecap.</dd>
1846
 
     *          </dl>
1847
 
     *      </dd>
1848
 
     *      <dt>linejoin</dt><dd>Specifies a linejoin for the stroke. The following values can be specified:
1849
 
     *          <dl>
1850
 
     *              <dt>round (default)</dt><dd>Specifies that the linejoin will be round.</dd>
1851
 
     *              <dt>bevel</dt><dd>Specifies a bevel for the linejoin.</dd>
1852
 
     *              <dt>miter limit</dt><dd>An integer specifying the miter limit of a miter linejoin. If you want to specify a linejoin of miter, you simply specify the limit as opposed to having
1853
 
     *  separate miter and miter limit values.</dd>
1854
 
     *          </dl>
1855
 
     *      </dd>
1856
 
     *  </dl>
1857
 
         *
1858
 
         * @config stroke
1859
 
         * @type Object
1860
 
         */
1861
 
        stroke: {
1862
 
                valueFn: "_getDefaultStroke",
1863
 
 
1864
 
                setter: function(val)
1865
 
                {
1866
 
                        var tmpl = this.get("stroke") || this._getDefaultStroke(),
1867
 
                wt;
1868
 
            if(val && val.hasOwnProperty("weight"))
1869
 
            {
1870
 
                wt = parseInt(val.weight, 10);
1871
 
                if(!isNaN(wt))
1872
 
                {
1873
 
                    val.weight = wt;
1874
 
                }
1875
 
            }
1876
 
                        val = (val) ? Y.merge(tmpl, val) : null;
1877
 
                        this._setStrokeProps(val);
1878
 
                        return val;
1879
 
                }
1880
 
        },
1881
 
        
1882
 
        //Not used. Remove in future.
1883
 
        autoSize: {
1884
 
                value: false
1885
 
        },
1886
 
 
1887
 
        // Only implemented in SVG
1888
 
        // Determines whether the instance will receive mouse events.
1889
 
        // 
1890
 
        // @config pointerEvents
1891
 
        // @type string
1892
 
        //
1893
 
        pointerEvents: {
1894
 
                value: "visiblePainted"
1895
 
        },
1896
 
 
1897
 
        /**
1898
 
         * Reference to the container Graphic.
1899
 
         *
1900
 
         * @config graphic
1901
 
         * @type Graphic
1902
 
         */
1903
 
        graphic: {
1904
 
                readOnly: true,
1905
 
 
1906
 
                getter: function()
1907
 
                {
1908
 
                        return this._graphic;
1909
 
                }
1910
 
    }
1911
 
};
1912
 
Y.CanvasShape = CanvasShape;
1913
 
/**
1914
 
 * <a href="http://www.w3.org/TR/html5/the-canvas-element.html">Canvas</a> implementation of the <a href="Path.html">`Path`</a> class. 
1915
 
 * `CanvasPath` is not intended to be used directly. Instead, use the <a href="Path.html">`Path`</a> class. 
1916
 
 * If the browser lacks <a href="http://www.w3.org/TR/SVG/">SVG</a> capabilities but has 
1917
 
 * <a href="http://www.w3.org/TR/html5/the-canvas-element.html">Canvas</a> capabilities, the <a href="Path.html">`Path`</a> 
1918
 
 * class will point to the `CanvasPath` class.
1919
 
 *
1920
 
 * @module graphics
1921
 
 * @class CanvasPath
1922
 
 * @extends CanvasShape
1923
 
 */
1924
 
CanvasPath = function(cfg)
1925
 
{
1926
 
        CanvasPath.superclass.constructor.apply(this, arguments);
1927
 
};
1928
 
CanvasPath.NAME = "canvasPath";
1929
 
Y.extend(CanvasPath, Y.CanvasShape, {
1930
 
    /**
1931
 
     * Indicates the type of shape
1932
 
     *
1933
 
     * @property _type
1934
 
     * @type String
1935
 
     * @private
1936
 
     */
1937
 
    _type: "path",
1938
 
 
1939
 
        /**
1940
 
         * Draws the shape.
1941
 
         *
1942
 
         * @method _draw
1943
 
         * @private
1944
 
         */
1945
 
    _draw: function()
1946
 
    {
1947
 
        this._closePath();
1948
 
    },
1949
 
 
1950
 
        /**
1951
 
         * Creates the dom node for the shape.
1952
 
         *
1953
 
     * @method createNode
1954
 
         * @return HTMLElement
1955
 
         * @private
1956
 
         */
1957
 
        createNode: function()
1958
 
        {
1959
 
                var node = Y.config.doc.createElement('canvas'),
1960
 
                        id = this.get("id");
1961
 
                this._context = node.getContext('2d');
1962
 
                node.setAttribute("overflow", "visible");
1963
 
        node.setAttribute("pointer-events", "none");
1964
 
        node.style.pointerEvents = "none";
1965
 
        node.style.overflow = "visible";
1966
 
                node.setAttribute("id", id);
1967
 
                id = "#" + id;
1968
 
                this.node = node;
1969
 
                this.addClass("yui3-" + SHAPE + " yui3-" + this.name);
1970
 
        },
1971
 
 
1972
 
    /**
1973
 
     * Completes a drawing operation. 
1974
 
     *
1975
 
     * @method end
1976
 
     */
1977
 
    end: function()
1978
 
    {
1979
 
        this._draw();
1980
 
    }
1981
 
});
1982
 
 
1983
 
CanvasPath.ATTRS = Y.merge(Y.CanvasShape.ATTRS, {
1984
 
        /**
1985
 
         * Indicates the width of the shape
1986
 
         *
1987
 
         * @config width
1988
 
         * @type Number
1989
 
         */
1990
 
        width: {
1991
 
                getter: function()
1992
 
                {
1993
 
                        var offset = this._stroke && this._strokeWeight ? (this._strokeWeight * 2) : 0;
1994
 
                        return this._width - offset;
1995
 
                },
1996
 
 
1997
 
                setter: function(val)
1998
 
                {
1999
 
                        this._width = val;
2000
 
                        return val;
2001
 
                }
2002
 
        },
2003
 
 
2004
 
        /**
2005
 
         * Indicates the height of the shape
2006
 
         *
2007
 
         * @config height
2008
 
         * @type Number
2009
 
         */
2010
 
        height: {
2011
 
                getter: function()
2012
 
                {
2013
 
                        var offset = this._stroke && this._strokeWeight ? (this._strokeWeight * 2) : 0;
2014
 
            return this._height - offset;
2015
 
                },
2016
 
 
2017
 
                setter: function(val)
2018
 
                {
2019
 
                        this._height = val;
2020
 
                        return val;
2021
 
                }
2022
 
        },
2023
 
        
2024
 
        /**
2025
 
         * Indicates the path used for the node.
2026
 
         *
2027
 
         * @config path
2028
 
         * @type String
2029
 
     * @readOnly
2030
 
         */
2031
 
        path: {
2032
 
        readOnly: true,
2033
 
 
2034
 
                getter: function()
2035
 
                {
2036
 
                        return this._path;
2037
 
                }
2038
 
        }
2039
 
});
2040
 
Y.CanvasPath = CanvasPath;
2041
 
/**
2042
 
 * <a href="http://www.w3.org/TR/html5/the-canvas-element.html">Canvas</a> implementation of the <a href="Rect.html">`Rect`</a> class. 
2043
 
 * `CanvasRect` is not intended to be used directly. Instead, use the <a href="Rect.html">`Rect`</a> class. 
2044
 
 * If the browser lacks <a href="http://www.w3.org/TR/SVG/">SVG</a> capabilities but has 
2045
 
 * <a href="http://www.w3.org/TR/html5/the-canvas-element.html">Canvas</a> capabilities, the <a href="Rect.html">`Rect`</a> 
2046
 
 * class will point to the `CanvasRect` class.
2047
 
 *
2048
 
 * @module graphics
2049
 
 * @class CanvasRect
2050
 
 * @constructor
2051
 
 */
2052
 
CanvasRect = function()
2053
 
{
2054
 
        CanvasRect.superclass.constructor.apply(this, arguments);
2055
 
};
2056
 
CanvasRect.NAME = "canvasRect";
2057
 
Y.extend(CanvasRect, Y.CanvasShape, {
2058
 
        /**
2059
 
         * Indicates the type of shape
2060
 
         *
2061
 
         * @property _type
2062
 
         * @type String
2063
 
     * @private
2064
 
         */
2065
 
        _type: "rect",
2066
 
 
2067
 
        /**
2068
 
         * Draws the shape.
2069
 
         *
2070
 
         * @method _draw
2071
 
         * @private
2072
 
         */
2073
 
        _draw: function()
2074
 
        {
2075
 
                var w = this.get("width"),
2076
 
                        h = this.get("height");
2077
 
                this.clear();
2078
 
        this.drawRect(0, 0, w, h);
2079
 
                this._closePath();
2080
 
        }
2081
 
});
2082
 
CanvasRect.ATTRS = Y.CanvasShape.ATTRS;
2083
 
Y.CanvasRect = CanvasRect;
2084
 
/**
2085
 
 * <a href="http://www.w3.org/TR/html5/the-canvas-element.html">Canvas</a> implementation of the <a href="Ellipse.html">`Ellipse`</a> class. 
2086
 
 * `CanvasEllipse` is not intended to be used directly. Instead, use the <a href="Ellipse.html">`Ellipse`</a> class. 
2087
 
 * If the browser lacks <a href="http://www.w3.org/TR/SVG/">SVG</a> capabilities but has 
2088
 
 * <a href="http://www.w3.org/TR/html5/the-canvas-element.html">Canvas</a> capabilities, the <a href="Ellipse.html">`Ellipse`</a> 
2089
 
 * class will point to the `CanvasEllipse` class.
2090
 
 *
2091
 
 * @module graphics
2092
 
 * @class CanvasEllipse
2093
 
 * @constructor
2094
 
 */
2095
 
CanvasEllipse = function(cfg)
2096
 
{
2097
 
        CanvasEllipse.superclass.constructor.apply(this, arguments);
2098
 
};
2099
 
 
2100
 
CanvasEllipse.NAME = "canvasEllipse";
2101
 
 
2102
 
Y.extend(CanvasEllipse, CanvasShape, {
2103
 
        /**
2104
 
         * Indicates the type of shape
2105
 
         *
2106
 
         * @property _type
2107
 
         * @type String
2108
 
     * @private
2109
 
         */
2110
 
        _type: "ellipse",
2111
 
 
2112
 
        /**
2113
 
     * Draws the shape.
2114
 
     *
2115
 
     * @method _draw
2116
 
         * @private
2117
 
         */
2118
 
        _draw: function()
2119
 
        {
2120
 
                var w = this.get("width"),
2121
 
                        h = this.get("height");
2122
 
                this.clear();
2123
 
        this.drawEllipse(0, 0, w, h);
2124
 
                this._closePath();
2125
 
        }
2126
 
});
2127
 
CanvasEllipse.ATTRS = CanvasShape.ATTRS;
2128
 
Y.CanvasEllipse = CanvasEllipse;
2129
 
/**
2130
 
 * <a href="http://www.w3.org/TR/html5/the-canvas-element.html">Canvas</a> implementation of the <a href="Circle.html">`Circle`</a> class. 
2131
 
 * `CanvasCircle` is not intended to be used directly. Instead, use the <a href="Circle.html">`Circle`</a> class. 
2132
 
 * If the browser lacks <a href="http://www.w3.org/TR/SVG/">SVG</a> capabilities but has 
2133
 
 * <a href="http://www.w3.org/TR/html5/the-canvas-element.html">Canvas</a> capabilities, the <a href="Circle.html">`Circle`</a> 
2134
 
 * class will point to the `CanvasCircle` class.
2135
 
 *
2136
 
 * @module graphics
2137
 
 * @class CanvasCircle
2138
 
 * @constructor
2139
 
 */
2140
 
CanvasCircle = function(cfg)
2141
 
{
2142
 
        CanvasCircle.superclass.constructor.apply(this, arguments);
2143
 
};
2144
 
    
2145
 
CanvasCircle.NAME = "canvasCircle";
2146
 
 
2147
 
Y.extend(CanvasCircle, Y.CanvasShape, {
2148
 
        /**
2149
 
         * Indicates the type of shape
2150
 
         *
2151
 
         * @property _type
2152
 
         * @type String
2153
 
     * @private
2154
 
         */
2155
 
        _type: "circle",
2156
 
 
2157
 
        /**
2158
 
     * Draws the shape.
2159
 
     *
2160
 
     * @method _draw
2161
 
         * @private
2162
 
         */
2163
 
        _draw: function()
2164
 
        {
2165
 
                var radius = this.get("radius");
2166
 
                if(radius)
2167
 
                {
2168
 
            this.clear();
2169
 
            this.drawCircle(0, 0, radius);
2170
 
                        this._closePath();
2171
 
                }
2172
 
        }
2173
 
});
2174
 
 
2175
 
CanvasCircle.ATTRS = Y.merge(Y.CanvasShape.ATTRS, {
2176
 
        /**
2177
 
         * Indicates the width of the shape
2178
 
         *
2179
 
         * @config width
2180
 
         * @type Number
2181
 
         */
2182
 
        width: {
2183
 
        setter: function(val)
2184
 
        {
2185
 
            this.set("radius", val/2);
2186
 
            return val;
2187
 
        },
2188
 
 
2189
 
                getter: function()
2190
 
                {
2191
 
                        return this.get("radius") * 2;
2192
 
                }
2193
 
        },
2194
 
 
2195
 
        /**
2196
 
         * Indicates the height of the shape
2197
 
         *
2198
 
         * @config height
2199
 
         * @type Number
2200
 
         */
2201
 
        height: {
2202
 
        setter: function(val)
2203
 
        {
2204
 
            this.set("radius", val/2);
2205
 
            return val;
2206
 
        },
2207
 
 
2208
 
                getter: function()
2209
 
                {
2210
 
                        return this.get("radius") * 2;
2211
 
                }
2212
 
        },
2213
 
 
2214
 
        /**
2215
 
         * Radius of the circle
2216
 
         *
2217
 
         * @config radius
2218
 
     * @type Number
2219
 
         */
2220
 
        radius: {
2221
 
                lazyAdd: false
2222
 
        }
2223
 
});
2224
 
Y.CanvasCircle = CanvasCircle;
2225
 
/**
2226
 
 * Draws pie slices
2227
 
 *
2228
 
 * @module graphics
2229
 
 * @class CanvasPieSlice
2230
 
 * @constructor
2231
 
 */
2232
 
CanvasPieSlice = function()
2233
 
{
2234
 
        CanvasPieSlice.superclass.constructor.apply(this, arguments);
2235
 
};
2236
 
CanvasPieSlice.NAME = "canvasPieSlice";
2237
 
Y.extend(CanvasPieSlice, Y.CanvasShape, {
2238
 
    /**
2239
 
     * Indicates the type of shape
2240
 
     *
2241
 
     * @property _type
2242
 
     * @type String
2243
 
     * @private
2244
 
     */
2245
 
    _type: "path",
2246
 
 
2247
 
        /**
2248
 
         * Change event listener
2249
 
         *
2250
 
         * @private
2251
 
         * @method _updateHandler
2252
 
         */
2253
 
        _draw: function(e)
2254
 
        {
2255
 
        var x = this.get("cx"),
2256
 
            y = this.get("cy"),
2257
 
            startAngle = this.get("startAngle"),
2258
 
            arc = this.get("arc"),
2259
 
            radius = this.get("radius");
2260
 
        this.clear();
2261
 
        this._left = x;
2262
 
        this._right = radius;
2263
 
        this._top = y;
2264
 
        this._bottom = radius;
2265
 
        this.drawWedge(x, y, startAngle, arc, radius);
2266
 
                this.end();
2267
 
        }
2268
 
 });
2269
 
CanvasPieSlice.ATTRS = Y.mix({
2270
 
    cx: {
2271
 
        value: 0
2272
 
    },
2273
 
 
2274
 
    cy: {
2275
 
        value: 0
2276
 
    },
2277
 
    /**
2278
 
     * Starting angle in relation to a circle in which to begin the pie slice drawing.
2279
 
     *
2280
 
     * @config startAngle
2281
 
     * @type Number
2282
 
     */
2283
 
    startAngle: {
2284
 
        value: 0
2285
 
    },
2286
 
 
2287
 
    /**
2288
 
     * Arc of the slice.
2289
 
     *
2290
 
     * @config arc
2291
 
     * @type Number
2292
 
     */
2293
 
    arc: {
2294
 
        value: 0
2295
 
    },
2296
 
 
2297
 
    /**
2298
 
     * Radius of the circle in which the pie slice is drawn
2299
 
     *
2300
 
     * @config radius
2301
 
     * @type Number
2302
 
     */
2303
 
    radius: {
2304
 
        value: 0
2305
 
    }
2306
 
}, Y.CanvasShape.ATTRS);
2307
 
Y.CanvasPieSlice = CanvasPieSlice;
2308
 
/**
2309
 
 * <a href="http://www.w3.org/TR/html5/the-canvas-element.html">Canvas</a> implementation of the `Graphic` class. 
2310
 
 * `CanvasGraphic` is not intended to be used directly. Instead, use the <a href="Graphic.html">`Graphic`</a> class. 
2311
 
 * If the browser lacks <a href="http://www.w3.org/TR/SVG/">SVG</a> capabilities but has 
2312
 
 * <a href="http://www.w3.org/TR/html5/the-canvas-element.html">Canvas</a> capabilities, the <a href="Graphic.html">`Graphic`</a> 
2313
 
 * class will point to the `CanvasGraphic` class.
2314
 
 *
2315
 
 * @module graphics
2316
 
 * @class CanvasGraphic
2317
 
 * @constructor
2318
 
 */
2319
 
function CanvasGraphic(config) {
2320
 
    
2321
 
    CanvasGraphic.superclass.constructor.apply(this, arguments);
2322
 
}
2323
 
 
2324
 
CanvasGraphic.NAME = "canvasGraphic";
2325
 
 
2326
 
CanvasGraphic.ATTRS = {
2327
 
    /**
2328
 
     * Whether or not to render the `Graphic` automatically after to a specified parent node after init. This can be a Node instance or a CSS selector string.
2329
 
     * 
2330
 
     * @config render
2331
 
     * @type Node | String 
2332
 
     */
2333
 
    render: {},
2334
 
        
2335
 
    /**
2336
 
         * Unique id for class instance.
2337
 
         *
2338
 
         * @config id
2339
 
         * @type String
2340
 
         */
2341
 
        id: {
2342
 
                valueFn: function()
2343
 
                {
2344
 
                        return Y.guid();
2345
 
                },
2346
 
 
2347
 
                setter: function(val)
2348
 
                {
2349
 
                        var node = this._node;
2350
 
                        if(node)
2351
 
                        {
2352
 
                                node.setAttribute("id", val);
2353
 
                        }
2354
 
                        return val;
2355
 
                }
2356
 
        },
2357
 
 
2358
 
    /**
2359
 
     * Key value pairs in which a shape instance is associated with its id.
2360
 
     *
2361
 
     *  @config shapes
2362
 
     *  @type Object
2363
 
     *  @readOnly
2364
 
     */
2365
 
    shapes: {
2366
 
        readOnly: true,
2367
 
 
2368
 
        getter: function()
2369
 
        {
2370
 
            return this._shapes;
2371
 
        }
2372
 
    },
2373
 
 
2374
 
    /**
2375
 
     *  Object containing size and coordinate data for the content of a Graphic in relation to the graphic instance's position.
2376
 
     *
2377
 
     *  @config contentBounds 
2378
 
     *  @type Object
2379
 
     *  @readOnly
2380
 
     */
2381
 
    contentBounds: {
2382
 
        readOnly: true,
2383
 
 
2384
 
        getter: function()
2385
 
        {
2386
 
            return this._contentBounds;
2387
 
        }
2388
 
    },
2389
 
 
2390
 
    /**
2391
 
     *  The outermost html element of the Graphic instance.
2392
 
     *
2393
 
     *  @config node
2394
 
     *  @type HTMLElement
2395
 
     *  @readOnly
2396
 
     */
2397
 
    node: {
2398
 
        readOnly: true,
2399
 
 
2400
 
        getter: function()
2401
 
        {
2402
 
            return this._node;
2403
 
        }
2404
 
    },
2405
 
 
2406
 
        /**
2407
 
         * Indicates the width of the `Graphic`. 
2408
 
         *
2409
 
         * @config width
2410
 
         * @type Number
2411
 
         */
2412
 
    width: {
2413
 
        setter: function(val)
2414
 
        {
2415
 
            if(this._node)
2416
 
            {
2417
 
                this._node.style.width = val + "px";            
2418
 
            }
2419
 
            return val;
2420
 
        }
2421
 
    },
2422
 
 
2423
 
        /**
2424
 
         * Indicates the height of the `Graphic`. 
2425
 
         *
2426
 
         * @config height 
2427
 
         * @type Number
2428
 
         */
2429
 
    height: {
2430
 
        setter: function(val)
2431
 
        {
2432
 
            if(this._node)
2433
 
            {
2434
 
                this._node.style.height = val + "px";
2435
 
            }
2436
 
            return val;
2437
 
        }
2438
 
    },
2439
 
 
2440
 
    /**
2441
 
     *  Determines how the size of instance is calculated. If true, the width and height are determined by the size of the contents.
2442
 
     *  If false, the width and height values are either explicitly set or determined by the size of the parent node's dimensions.
2443
 
     *
2444
 
     *  @config autoSize
2445
 
     *  @type Boolean
2446
 
     *  @default false
2447
 
     */
2448
 
    autoSize: {
2449
 
        value: false
2450
 
    },
2451
 
 
2452
 
    /**
2453
 
     * The contentBounds will resize to greater values but not smaller values. (for performance)
2454
 
     * When resizing the contentBounds down is desirable, set the resizeDown value to true.
2455
 
     *
2456
 
     * @config resizeDown 
2457
 
     * @type Boolean
2458
 
     */
2459
 
    resizeDown: {
2460
 
        getter: function()
2461
 
        {
2462
 
            return this._resizeDown;
2463
 
        },
2464
 
 
2465
 
        setter: function(val)
2466
 
        {
2467
 
            this._resizeDown = val;
2468
 
            if(this._node)
2469
 
            {
2470
 
                this._redraw();
2471
 
            }
2472
 
            return val;
2473
 
        }
2474
 
    },
2475
 
 
2476
 
        /**
2477
 
         * Indicates the x-coordinate for the instance.
2478
 
         *
2479
 
         * @config x
2480
 
         * @type Number
2481
 
         */
2482
 
    x: {
2483
 
        getter: function()
2484
 
        {
2485
 
            return this._x;
2486
 
        },
2487
 
 
2488
 
        setter: function(val)
2489
 
        {
2490
 
            this._x = val;
2491
 
            if(this._node)
2492
 
            {
2493
 
                this._node.style.left = val + "px";
2494
 
            }
2495
 
            return val;
2496
 
        }
2497
 
    },
2498
 
 
2499
 
        /**
2500
 
         * Indicates the y-coordinate for the instance.
2501
 
         *
2502
 
         * @config y
2503
 
         * @type Number
2504
 
         */
2505
 
    y: {
2506
 
        getter: function()
2507
 
        {
2508
 
            return this._y;
2509
 
        },
2510
 
 
2511
 
        setter: function(val)
2512
 
        {
2513
 
            this._y = val;
2514
 
            if(this._node)
2515
 
            {
2516
 
                this._node.style.top = val + "px";
2517
 
            }
2518
 
            return val;
2519
 
        }
2520
 
    },
2521
 
 
2522
 
    /**
2523
 
     * Indicates whether or not the instance will automatically redraw after a change is made to a shape.
2524
 
     * This property will get set to false when batching operations.
2525
 
     *
2526
 
     * @config autoDraw
2527
 
     * @type Boolean
2528
 
     * @default true
2529
 
     * @private
2530
 
     */
2531
 
    autoDraw: {
2532
 
        value: true
2533
 
    },
2534
 
 
2535
 
        /**
2536
 
         * Indicates whether the `Graphic` and its children are visible.
2537
 
         *
2538
 
         * @config visible
2539
 
         * @type Boolean
2540
 
         */
2541
 
    visible: {
2542
 
        value: true,
2543
 
 
2544
 
        setter: function(val)
2545
 
        {
2546
 
            this._toggleVisible(val);
2547
 
            return val;
2548
 
        }
2549
 
    }
2550
 
};
2551
 
 
2552
 
Y.extend(CanvasGraphic, Y.GraphicBase, {
2553
 
    /**
2554
 
     * Storage for `x` attribute.
2555
 
     *
2556
 
     * @property _x
2557
 
     * @type Number
2558
 
     * @private
2559
 
     */
2560
 
    _x: 0,
2561
 
 
2562
 
    /**
2563
 
     * Storage for `y` attribute.
2564
 
     *
2565
 
     * @property _y
2566
 
     * @type Number
2567
 
     * @private
2568
 
     */
2569
 
    _y: 0,
2570
 
 
2571
 
    /**
2572
 
     * Gets the current position of the graphic instance in page coordinates.
2573
 
     *
2574
 
     * @method getXY
2575
 
     * @return Array The XY position of the shape.
2576
 
     */
2577
 
    getXY: function()
2578
 
    {
2579
 
        var node = Y.one(this._node),
2580
 
            xy;
2581
 
        if(node)
2582
 
        {
2583
 
            xy = node.getXY();
2584
 
        }
2585
 
        return xy;
2586
 
    },
2587
 
 
2588
 
    /**
2589
 
     * Storage for `resizeDown` attribute.
2590
 
     *
2591
 
     * @property _resizeDown 
2592
 
     * @type Boolean
2593
 
     * @private
2594
 
     */
2595
 
    _resizeDown: false,
2596
 
    
2597
 
        /**
2598
 
     * Initializes the class.
2599
 
     *
2600
 
     * @method initializer
2601
 
     * @param {Object} config Optional attributes 
2602
 
     * @private
2603
 
     */
2604
 
    initializer: function(config) {
2605
 
        var render = this.get("render"),
2606
 
            w = this.get("width") || 0,
2607
 
            h = this.get("height") || 0;
2608
 
        this._shapes = {};
2609
 
        this._redrawQueue = {};
2610
 
                this._contentBounds = {
2611
 
            left: 0,
2612
 
            top: 0,
2613
 
            right: 0,
2614
 
            bottom: 0
2615
 
        };
2616
 
        this._node = DOCUMENT.createElement('div');
2617
 
        this._node.style.position = "absolute";
2618
 
        this.set("width", w);
2619
 
        this.set("height", h);
2620
 
        if(render)
2621
 
        {
2622
 
            this.render(render);
2623
 
        }
2624
 
    },
2625
 
 
2626
 
    /**
2627
 
     * Adds the graphics node to the dom.
2628
 
     * 
2629
 
     * @method render
2630
 
     * @param {HTMLElement} parentNode node in which to render the graphics node into.
2631
 
     */
2632
 
    render: function(render) {
2633
 
        var parentNode = Y.one(render),
2634
 
            node = this._node,
2635
 
            w = this.get("width") || parseInt(parentNode.getComputedStyle("width"), 10),
2636
 
            h = this.get("height") || parseInt(parentNode.getComputedStyle("height"), 10);
2637
 
        parentNode = parentNode || DOCUMENT.body;
2638
 
        parentNode.appendChild(node);
2639
 
        node.style.display = "block";
2640
 
        node.style.position = "absolute";
2641
 
        node.style.left = "0px";
2642
 
        node.style.top = "0px";
2643
 
        this.set("width", w);
2644
 
        this.set("height", h);
2645
 
        this.parentNode = parentNode;
2646
 
        return this;
2647
 
    },
2648
 
 
2649
 
    /**
2650
 
     * Removes all nodes.
2651
 
     *
2652
 
     * @method destroy
2653
 
     */
2654
 
    destroy: function()
2655
 
    {
2656
 
        this.removeAllShapes();
2657
 
        if(this._node)
2658
 
        {
2659
 
            this._removeChildren(this._node);
2660
 
            Y.one(this._node).destroy();
2661
 
        }
2662
 
    },
2663
 
 
2664
 
    /**
2665
 
     * Generates a shape instance by type.
2666
 
     *
2667
 
     * @method addShape
2668
 
     * @param {Object} cfg attributes for the shape
2669
 
     * @return Shape
2670
 
     */
2671
 
    addShape: function(cfg)
2672
 
    {
2673
 
        cfg.graphic = this;
2674
 
        var shapeClass = this._getShapeClass(cfg.type),
2675
 
            shape = new shapeClass(cfg);
2676
 
        this._appendShape(shape);
2677
 
        return shape;
2678
 
    },
2679
 
 
2680
 
    /**
2681
 
     * Adds a shape instance to the graphic instance.
2682
 
     *
2683
 
     * @method _appendShape
2684
 
     * @param {Shape} shape The shape instance to be added to the graphic.
2685
 
     * @private
2686
 
     */
2687
 
    _appendShape: function(shape)
2688
 
    {
2689
 
        var node = shape.node,
2690
 
            parentNode = this._frag || this._node;
2691
 
        if(this.get("autoDraw")) 
2692
 
        {
2693
 
            parentNode.appendChild(node);
2694
 
        }
2695
 
        else
2696
 
        {
2697
 
            this._getDocFrag().appendChild(node);
2698
 
        }
2699
 
    },
2700
 
 
2701
 
    /**
2702
 
     * Removes a shape instance from from the graphic instance.
2703
 
     *
2704
 
     * @method removeShape
2705
 
     * @param {Shape|String} shape The instance or id of the shape to be removed.
2706
 
     */
2707
 
    removeShape: function(shape)
2708
 
    {
2709
 
        if(!(shape instanceof CanvasShape))
2710
 
        {
2711
 
            if(Y_LANG.isString(shape))
2712
 
            {
2713
 
                shape = this._shapes[shape];
2714
 
            }
2715
 
        }
2716
 
        if(shape && shape instanceof CanvasShape)
2717
 
        {
2718
 
            shape._destroy();
2719
 
            delete this._shapes[shape.get("id")];
2720
 
        }
2721
 
        if(this.get("autoDraw")) 
2722
 
        {
2723
 
            this._redraw();
2724
 
        }
2725
 
        return shape;
2726
 
    },
2727
 
 
2728
 
    /**
2729
 
     * Removes all shape instances from the dom.
2730
 
     *
2731
 
     * @method removeAllShapes
2732
 
     */
2733
 
    removeAllShapes: function()
2734
 
    {
2735
 
        var shapes = this._shapes,
2736
 
            i;
2737
 
        for(i in shapes)
2738
 
        {
2739
 
            if(shapes.hasOwnProperty(i))
2740
 
            {
2741
 
                shapes[i].destroy();
2742
 
            }
2743
 
        }
2744
 
        this._shapes = {};
2745
 
    },
2746
 
    
2747
 
    /**
2748
 
     * Removes all child nodes.
2749
 
     *
2750
 
     * @method _removeChildren
2751
 
     * @param {HTMLElement} node
2752
 
     * @private
2753
 
     */
2754
 
    _removeChildren: function(node)
2755
 
    {
2756
 
        if(node && node.hasChildNodes())
2757
 
        {
2758
 
            var child;
2759
 
            while(node.firstChild)
2760
 
            {
2761
 
                child = node.firstChild;
2762
 
                this._removeChildren(child);
2763
 
                node.removeChild(child);
2764
 
            }
2765
 
        }
2766
 
    },
2767
 
    
2768
 
    /**
2769
 
     * Toggles visibility
2770
 
     *
2771
 
     * @method _toggleVisible
2772
 
     * @param {Boolean} val indicates visibilitye
2773
 
     * @private
2774
 
     */
2775
 
    _toggleVisible: function(val)
2776
 
    {
2777
 
        var i,
2778
 
            shapes = this._shapes,
2779
 
            visibility = val ? "visible" : "hidden";
2780
 
        if(shapes)
2781
 
        {
2782
 
            for(i in shapes)
2783
 
            {
2784
 
                if(shapes.hasOwnProperty(i))
2785
 
                {
2786
 
                    shapes[i].set("visible", val);
2787
 
                }
2788
 
            }
2789
 
        }
2790
 
        this._node.style.visibility = visibility;
2791
 
    },
2792
 
 
2793
 
    /**
2794
 
     * Returns a shape class. Used by `addShape`. 
2795
 
     *
2796
 
     * @method _getShapeClass
2797
 
     * @param {Shape | String} val Indicates which shape class. 
2798
 
     * @return Function 
2799
 
     * @private
2800
 
     */
2801
 
    _getShapeClass: function(val)
2802
 
    {
2803
 
        var shape = this._shapeClass[val];
2804
 
        if(shape)
2805
 
        {
2806
 
            return shape;
2807
 
        }
2808
 
        return val;
2809
 
    },
2810
 
    
2811
 
    /**
2812
 
     * Look up for shape classes. Used by `addShape` to retrieve a class for instantiation.
2813
 
     *
2814
 
     * @property _shapeClass
2815
 
     * @type Object
2816
 
     * @private
2817
 
     */
2818
 
    _shapeClass: {
2819
 
        circle: Y.CanvasCircle,
2820
 
        rect: Y.CanvasRect,
2821
 
        path: Y.CanvasPath,
2822
 
        ellipse: Y.CanvasEllipse,
2823
 
        pieslice: Y.CanvasPieSlice
2824
 
    },
2825
 
    
2826
 
    /**
2827
 
     * Returns a shape based on the id of its dom node.
2828
 
     *
2829
 
     * @method getShapeById
2830
 
     * @param {String} id Dom id of the shape's node attribute.
2831
 
     * @return Shape
2832
 
     */
2833
 
    getShapeById: function(id)
2834
 
    {
2835
 
        var shape = this._shapes[id];
2836
 
        return shape;
2837
 
    },
2838
 
 
2839
 
        /**
2840
 
         * Allows for creating multiple shapes in order to batch appending and redraw operations.
2841
 
         *
2842
 
         * @method batch
2843
 
         * @param {Function} method Method to execute.
2844
 
         */
2845
 
    batch: function(method)
2846
 
    {
2847
 
        var autoDraw = this.get("autoDraw");
2848
 
        this.set("autoDraw", false);
2849
 
        method();
2850
 
        this._redraw();
2851
 
        this.set("autoDraw", autoDraw);
2852
 
    },
2853
 
 
2854
 
    /**
2855
 
     * Returns a document fragment to for attaching shapes.
2856
 
     *
2857
 
     * @method _getDocFrag
2858
 
     * @return DocumentFragment
2859
 
     * @private
2860
 
     */
2861
 
    _getDocFrag: function()
2862
 
    {
2863
 
        if(!this._frag)
2864
 
        {
2865
 
            this._frag = DOCUMENT.createDocumentFragment();
2866
 
        }
2867
 
        return this._frag;
2868
 
    },
2869
 
    
2870
 
    /**
2871
 
     * Redraws all shapes.
2872
 
     *
2873
 
     * @method _redraw
2874
 
     * @private
2875
 
     */
2876
 
    _redraw: function()
2877
 
    {
2878
 
        var box = this.get("resizeDown") ? this._getUpdatedContentBounds() : this._contentBounds;
2879
 
        if(this.get("autoSize"))
2880
 
        {
2881
 
            this.set("width", box.right);
2882
 
            this.set("height", box.bottom);
2883
 
        }
2884
 
        if(this._frag)
2885
 
        {
2886
 
            this._node.appendChild(this._frag);
2887
 
            this._frag = null;
2888
 
        }
2889
 
    },
2890
 
 
2891
 
    /**
2892
 
     * Adds a shape to the redraw queue and calculates the contentBounds. Used internally 
2893
 
     * by `Shape` instances.
2894
 
     *
2895
 
     * @method addToRedrawQueue
2896
 
     * @param Shape shape The shape instance to add to the queue
2897
 
     * @protected
2898
 
     */
2899
 
    addToRedrawQueue: function(shape)
2900
 
    {
2901
 
        var shapeBox,
2902
 
            box;
2903
 
        this._shapes[shape.get("id")] = shape;
2904
 
        if(!this.get("resizeDown"))
2905
 
        {
2906
 
            shapeBox = shape.getBounds();
2907
 
            box = this._contentBounds;
2908
 
            box.left = box.left < shapeBox.left ? box.left : shapeBox.left;
2909
 
            box.top = box.top < shapeBox.top ? box.top : shapeBox.top;
2910
 
            box.right = box.right > shapeBox.right ? box.right : shapeBox.right;
2911
 
            box.bottom = box.bottom > shapeBox.bottom ? box.bottom : shapeBox.bottom;
2912
 
            box.width = box.right - box.left;
2913
 
            box.height = box.bottom - box.top;
2914
 
            this._contentBounds = box;
2915
 
        }
2916
 
        if(this.get("autoDraw")) 
2917
 
        {
2918
 
            this._redraw();
2919
 
        }
2920
 
    },
2921
 
 
2922
 
    /**
2923
 
     * Recalculates and returns the `contentBounds` for the `Graphic` instance.
2924
 
     *
2925
 
     * @method _getUpdatedContentBounds
2926
 
     * @return {Object} 
2927
 
     * @private
2928
 
     */
2929
 
    _getUpdatedContentBounds: function()
2930
 
    {
2931
 
        var bounds,
2932
 
            i,
2933
 
            shape,
2934
 
            queue = this._shapes,
2935
 
            box = {
2936
 
                left: 0,
2937
 
                top: 0,
2938
 
                right: 0,
2939
 
                bottom: 0
2940
 
            };
2941
 
        for(i in queue)
2942
 
        {
2943
 
            if(queue.hasOwnProperty(i))
2944
 
            {
2945
 
                shape = queue[i];
2946
 
                bounds = shape.getBounds();
2947
 
                box.left = Math.min(box.left, bounds.left);
2948
 
                box.top = Math.min(box.top, bounds.top);
2949
 
                box.right = Math.max(box.right, bounds.right);
2950
 
                box.bottom = Math.max(box.bottom, bounds.bottom);
2951
 
            }
2952
 
        }
2953
 
        box.width = box.right - box.left;
2954
 
        box.height = box.bottom - box.top;
2955
 
        this._contentBounds = box;
2956
 
        return box;
2957
 
    }
2958
 
});
2959
 
 
2960
 
Y.CanvasGraphic = CanvasGraphic;
2961
 
 
2962
 
 
2963
 
}, '3.5.1' ,{skinnable:false, requires:['graphics']});