~ubuntu-branches/ubuntu/utopic/moodle/utopic

« back to all changes in this revision

Viewing changes to lib/yuilib/3.9.1/build/graphics-svg/graphics-svg-debug.js

  • Committer: Package Import Robot
  • Author(s): Thijs Kinkhorst
  • Date: 2014-05-12 16:10:38 UTC
  • mfrom: (36.1.3 sid)
  • Revision ID: package-import@ubuntu.com-20140512161038-puyqf65k4e0s8ytz
Tags: 2.6.3-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* YUI 3.9.1 (build 5852) Copyright 2013 Yahoo! Inc. http://yuilibrary.com/license/ */
2
 
YUI.add('graphics-svg', function (Y, NAME) {
3
 
 
4
 
var IMPLEMENTATION = "svg",
5
 
    SHAPE = "shape",
6
 
        SPLITPATHPATTERN = /[a-z][^a-z]*/ig,
7
 
    SPLITARGSPATTERN = /[\-]?[0-9]*[0-9|\.][0-9]*/g,
8
 
    Y_LANG = Y.Lang,
9
 
        AttributeLite = Y.AttributeLite,
10
 
        SVGGraphic,
11
 
    SVGShape,
12
 
        SVGCircle,
13
 
        SVGRect,
14
 
        SVGPath,
15
 
        SVGEllipse,
16
 
    SVGPieSlice,
17
 
    DOCUMENT = Y.config.doc,
18
 
    _getClassName = Y.ClassNameManager.getClassName;
19
 
 
20
 
function SVGDrawing(){}
21
 
 
22
 
/**
23
 
 * <a href="http://www.w3.org/TR/SVG/">SVG</a> implementation of the <a href="Drawing.html">`Drawing`</a> class.
24
 
 * `SVGDrawing` is not intended to be used directly. Instead, use the <a href="Drawing.html">`Drawing`</a> class.
25
 
 * If the browser has <a href="http://www.w3.org/TR/SVG/">SVG</a> capabilities, the <a href="Drawing.html">`Drawing`</a>
26
 
 * class will point to the `SVGDrawing` class.
27
 
 *
28
 
 * @module graphics
29
 
 * @class SVGDrawing
30
 
 * @constructor
31
 
 */
32
 
SVGDrawing.prototype = {
33
 
    /**
34
 
     * Maps path to methods
35
 
     *
36
 
     * @property _pathSymbolToMethod
37
 
     * @type Object
38
 
     * @private
39
 
     */
40
 
    _pathSymbolToMethod: {
41
 
        M: "moveTo",
42
 
        m: "relativeMoveTo",
43
 
        L: "lineTo",
44
 
        l: "relativeLineTo",
45
 
        C: "curveTo",
46
 
        c: "relativeCurveTo",
47
 
        Q: "quadraticCurveTo",
48
 
        q: "relativeQuadraticCurveTo",
49
 
        z: "closePath",
50
 
        Z: "closePath"
51
 
    },
52
 
 
53
 
    /**
54
 
     * Current x position of the drawing.
55
 
     *
56
 
     * @property _currentX
57
 
     * @type Number
58
 
     * @private
59
 
     */
60
 
    _currentX: 0,
61
 
 
62
 
    /**
63
 
     * Current y position of the drqwing.
64
 
     *
65
 
     * @property _currentY
66
 
     * @type Number
67
 
     * @private
68
 
     */
69
 
    _currentY: 0,
70
 
 
71
 
    /**
72
 
     * Indicates the type of shape
73
 
     *
74
 
     * @private
75
 
     * @property _type
76
 
     * @readOnly
77
 
     * @type String
78
 
     */
79
 
    _type: "path",
80
 
 
81
 
    /**
82
 
     * Draws a bezier curve.
83
 
     *
84
 
     * @method curveTo
85
 
     * @param {Number} cp1x x-coordinate for the first control point.
86
 
     * @param {Number} cp1y y-coordinate for the first control point.
87
 
     * @param {Number} cp2x x-coordinate for the second control point.
88
 
     * @param {Number} cp2y y-coordinate for the second control point.
89
 
     * @param {Number} x x-coordinate for the end point.
90
 
     * @param {Number} y y-coordinate for the end point.
91
 
     * @chainable
92
 
     */
93
 
    curveTo: function() {
94
 
        this._curveTo.apply(this, [Y.Array(arguments), false]);
95
 
        return this;
96
 
    },
97
 
 
98
 
    /**
99
 
     * Draws a bezier curve relative to the current coordinates.
100
 
     *
101
 
     * @method relativeCurveTo
102
 
     * @param {Number} cp1x x-coordinate for the first control point.
103
 
     * @param {Number} cp1y y-coordinate for the first control point.
104
 
     * @param {Number} cp2x x-coordinate for the second control point.
105
 
     * @param {Number} cp2y y-coordinate for the second control point.
106
 
     * @param {Number} x x-coordinate for the end point.
107
 
     * @param {Number} y y-coordinate for the end point.
108
 
     * @chainable
109
 
     */
110
 
    relativeCurveTo: function() {
111
 
        this._curveTo.apply(this, [Y.Array(arguments), true]);
112
 
        return this;
113
 
    },
114
 
 
115
 
    /**
116
 
     * Implements curveTo methods.
117
 
     *
118
 
     * @method _curveTo
119
 
     * @param {Array} args The arguments to be used.
120
 
     * @param {Boolean} relative Indicates whether or not to use relative coordinates.
121
 
     * @private
122
 
     */
123
 
    _curveTo: function(args, relative) {
124
 
        var w,
125
 
            h,
126
 
            pts,
127
 
            cp1x,
128
 
            cp1y,
129
 
            cp2x,
130
 
            cp2y,
131
 
            x,
132
 
            y,
133
 
            right,
134
 
            left,
135
 
            bottom,
136
 
            top,
137
 
            i,
138
 
            len,
139
 
            pathArrayLen,
140
 
            currentArray,
141
 
            command = relative ? "c" : "C",
142
 
            relativeX = relative ? parseFloat(this._currentX) : 0,
143
 
            relativeY = relative ? parseFloat(this._currentY) : 0;
144
 
        this._pathArray = this._pathArray || [];
145
 
        if(this._pathType !== command)
146
 
        {
147
 
            this._pathType = command;
148
 
            currentArray = [command];
149
 
            this._pathArray.push(currentArray);
150
 
        }
151
 
        else
152
 
        {
153
 
            currentArray = this._pathArray[Math.max(0, this._pathArray.length - 1)];
154
 
            if(!currentArray)
155
 
            {
156
 
                currentArray = [];
157
 
                this._pathArray.push(currentArray);
158
 
            }
159
 
        }
160
 
        pathArrayLen = this._pathArray.length - 1;
161
 
        this._pathArray[pathArrayLen] = this._pathArray[pathArrayLen].concat(args);
162
 
        len = args.length - 5;
163
 
        for(i = 0; i < len; i = i + 6)
164
 
        {
165
 
            cp1x = parseFloat(args[i]) + relativeX;
166
 
            cp1y = parseFloat(args[i + 1]) + relativeY;
167
 
            cp2x = parseFloat(args[i + 2]) + relativeX;
168
 
            cp2y = parseFloat(args[i + 3]) + relativeY;
169
 
            x = parseFloat(args[i + 4]) + relativeX;
170
 
            y = parseFloat(args[i + 5]) + relativeY;
171
 
            right = Math.max(x, Math.max(cp1x, cp2x));
172
 
            bottom = Math.max(y, Math.max(cp1y, cp2y));
173
 
            left = Math.min(x, Math.min(cp1x, cp2x));
174
 
            top = Math.min(y, Math.min(cp1y, cp2y));
175
 
            w = Math.abs(right - left);
176
 
            h = Math.abs(bottom - top);
177
 
            pts = [[this._currentX, this._currentY] , [cp1x, cp1y], [cp2x, cp2y], [x, y]];
178
 
            this._setCurveBoundingBox(pts, w, h);
179
 
            this._currentX = x;
180
 
            this._currentY = y;
181
 
        }
182
 
    },
183
 
 
184
 
    /**
185
 
     * Draws a quadratic bezier curve.
186
 
     *
187
 
     * @method quadraticCurveTo
188
 
     * @param {Number} cpx x-coordinate for the control point.
189
 
     * @param {Number} cpy y-coordinate for the control point.
190
 
     * @param {Number} x x-coordinate for the end point.
191
 
     * @param {Number} y y-coordinate for the end point.
192
 
     * @chainable
193
 
     */
194
 
    quadraticCurveTo: function() {
195
 
        this._quadraticCurveTo.apply(this, [Y.Array(arguments), false]);
196
 
        return this;
197
 
    },
198
 
 
199
 
    /**
200
 
     * Draws a quadratic bezier curve relative to the current position.
201
 
     *
202
 
     * @method quadraticCurveTo
203
 
     * @param {Number} cpx x-coordinate for the control point.
204
 
     * @param {Number} cpy y-coordinate for the control point.
205
 
     * @param {Number} x x-coordinate for the end point.
206
 
     * @param {Number} y y-coordinate for the end point.
207
 
     * @chainable
208
 
     */
209
 
    relativeQuadraticCurveTo: function() {
210
 
        this._quadraticCurveTo.apply(this, [Y.Array(arguments), true]);
211
 
        return this;
212
 
    },
213
 
 
214
 
    /**
215
 
     * Implements quadraticCurveTo methods.
216
 
     *
217
 
     * @method _quadraticCurveTo
218
 
     * @param {Array} args The arguments to be used.
219
 
     * @param {Boolean} relative Indicates whether or not to use relative coordinates.
220
 
     * @private
221
 
     */
222
 
    _quadraticCurveTo: function(args, relative) {
223
 
        var cpx,
224
 
            cpy,
225
 
            x,
226
 
            y,
227
 
            pathArrayLen,
228
 
            currentArray,
229
 
            w,
230
 
            h,
231
 
            pts,
232
 
            right,
233
 
            left,
234
 
            bottom,
235
 
            top,
236
 
            i,
237
 
            len,
238
 
            command = relative ? "q" : "Q",
239
 
            relativeX = relative ? parseFloat(this._currentX) : 0,
240
 
            relativeY = relative ? parseFloat(this._currentY) : 0;
241
 
        this._pathArray = this._pathArray || [];
242
 
        if(this._pathType !== command)
243
 
        {
244
 
            this._pathType = command;
245
 
            currentArray = [command];
246
 
            this._pathArray.push(currentArray);
247
 
        }
248
 
        else
249
 
        {
250
 
            currentArray = this._pathArray[Math.max(0, this._pathArray.length - 1)];
251
 
            if(!currentArray)
252
 
            {
253
 
                currentArray = [];
254
 
                this._pathArray.push(currentArray);
255
 
            }
256
 
        }
257
 
        pathArrayLen = this._pathArray.length - 1;
258
 
        this._pathArray[pathArrayLen] = this._pathArray[pathArrayLen].concat(args);
259
 
        len = args.length - 3;
260
 
        for(i = 0; i < len; i = i + 4)
261
 
        {
262
 
            cpx = parseFloat(args[i]) + relativeX;
263
 
            cpy = parseFloat(args[i + 1]) + relativeY;
264
 
            x = parseFloat(args[i + 2]) + relativeX;
265
 
            y = parseFloat(args[i + 3]) + relativeY;
266
 
            right = Math.max(x, cpx);
267
 
            bottom = Math.max(y, cpy);
268
 
            left = Math.min(x, cpx);
269
 
            top = Math.min(y, cpy);
270
 
            w = Math.abs(right - left);
271
 
            h = Math.abs(bottom - top);
272
 
            pts = [[this._currentX, this._currentY] , [cpx, cpy], [x, y]];
273
 
            this._setCurveBoundingBox(pts, w, h);
274
 
            this._currentX = x;
275
 
            this._currentY = y;
276
 
        }
277
 
    },
278
 
 
279
 
    /**
280
 
     * Draws a rectangle.
281
 
     *
282
 
     * @method drawRect
283
 
     * @param {Number} x x-coordinate
284
 
     * @param {Number} y y-coordinate
285
 
     * @param {Number} w width
286
 
     * @param {Number} h height
287
 
     * @chainable
288
 
     */
289
 
    drawRect: function(x, y, w, h) {
290
 
        this.moveTo(x, y);
291
 
        this.lineTo(x + w, y);
292
 
        this.lineTo(x + w, y + h);
293
 
        this.lineTo(x, y + h);
294
 
        this.lineTo(x, y);
295
 
        return this;
296
 
    },
297
 
 
298
 
    /**
299
 
     * Draws a rectangle with rounded corners.
300
 
     *
301
 
     * @method drawRoundRect
302
 
     * @param {Number} x x-coordinate
303
 
     * @param {Number} y y-coordinate
304
 
     * @param {Number} w width
305
 
     * @param {Number} h height
306
 
     * @param {Number} ew width of the ellipse used to draw the rounded corners
307
 
     * @param {Number} eh height of the ellipse used to draw the rounded corners
308
 
     * @chainable
309
 
     */
310
 
    drawRoundRect: function(x, y, w, h, ew, eh) {
311
 
        this.moveTo(x, y + eh);
312
 
        this.lineTo(x, y + h - eh);
313
 
        this.quadraticCurveTo(x, y + h, x + ew, y + h);
314
 
        this.lineTo(x + w - ew, y + h);
315
 
        this.quadraticCurveTo(x + w, y + h, x + w, y + h - eh);
316
 
        this.lineTo(x + w, y + eh);
317
 
        this.quadraticCurveTo(x + w, y, x + w - ew, y);
318
 
        this.lineTo(x + ew, y);
319
 
        this.quadraticCurveTo(x, y, x, y + eh);
320
 
        return this;
321
 
        },
322
 
 
323
 
    /**
324
 
     * Draws a circle.
325
 
     *
326
 
     * @method drawCircle
327
 
     * @param {Number} x y-coordinate
328
 
     * @param {Number} y x-coordinate
329
 
     * @param {Number} r radius
330
 
     * @chainable
331
 
     * @protected
332
 
     */
333
 
        drawCircle: function(x, y, radius) {
334
 
        var circum = radius * 2;
335
 
        this._drawingComplete = false;
336
 
        this._trackSize(x, y);
337
 
        this._trackSize(x + circum, y + circum);
338
 
        this._pathArray = this._pathArray || [];
339
 
        this._pathArray.push(["M", x + radius, y]);
340
 
        this._pathArray.push(["A",  radius, radius, 0, 1, 0, x + radius, y + circum]);
341
 
        this._pathArray.push(["A",  radius, radius, 0, 1, 0, x + radius, y]);
342
 
        this._currentX = x;
343
 
        this._currentY = y;
344
 
        return this;
345
 
    },
346
 
 
347
 
    /**
348
 
     * Draws an ellipse.
349
 
     *
350
 
     * @method drawEllipse
351
 
     * @param {Number} x x-coordinate
352
 
     * @param {Number} y y-coordinate
353
 
     * @param {Number} w width
354
 
     * @param {Number} h height
355
 
     * @chainable
356
 
     * @protected
357
 
     */
358
 
        drawEllipse: function(x, y, w, h) {
359
 
        var radius = w * 0.5,
360
 
            yRadius = h * 0.5;
361
 
        this._drawingComplete = false;
362
 
        this._trackSize(x, y);
363
 
        this._trackSize(x + w, y + h);
364
 
        this._pathArray = this._pathArray || [];
365
 
        this._pathArray.push(["M", x + radius, y]);
366
 
        this._pathArray.push(["A",  radius, yRadius, 0, 1, 0, x + radius, y + h]);
367
 
        this._pathArray.push(["A",  radius, yRadius, 0, 1, 0, x + radius, y]);
368
 
        this._currentX = x;
369
 
        this._currentY = y;
370
 
        return this;
371
 
    },
372
 
 
373
 
    /**
374
 
     * Draws a diamond.
375
 
     *
376
 
     * @method drawDiamond
377
 
     * @param {Number} x y-coordinate
378
 
     * @param {Number} y x-coordinate
379
 
     * @param {Number} width width
380
 
     * @param {Number} height height
381
 
     * @chainable
382
 
     * @protected
383
 
     */
384
 
    drawDiamond: function(x, y, width, height)
385
 
    {
386
 
        var midWidth = width * 0.5,
387
 
            midHeight = height * 0.5;
388
 
        this.moveTo(x + midWidth, y);
389
 
        this.lineTo(x + width, y + midHeight);
390
 
        this.lineTo(x + midWidth, y + height);
391
 
        this.lineTo(x, y + midHeight);
392
 
        this.lineTo(x + midWidth, y);
393
 
        return this;
394
 
    },
395
 
 
396
 
    /**
397
 
     * Draws a wedge.
398
 
     *
399
 
     * @method drawWedge
400
 
     * @param {Number} x x-coordinate of the wedge's center point
401
 
     * @param {Number} y y-coordinate of the wedge's center point
402
 
     * @param {Number} startAngle starting angle in degrees
403
 
     * @param {Number} arc sweep of the wedge. Negative values draw clockwise.
404
 
     * @param {Number} radius radius of wedge. If [optional] yRadius is defined, then radius is the x radius.
405
 
     * @param {Number} yRadius [optional] y radius for wedge.
406
 
     * @chainable
407
 
     * @private
408
 
     */
409
 
    drawWedge: function(x, y, startAngle, arc, radius, yRadius)
410
 
    {
411
 
        var segs,
412
 
            segAngle,
413
 
            theta,
414
 
            angle,
415
 
            angleMid,
416
 
            ax,
417
 
            ay,
418
 
            bx,
419
 
            by,
420
 
            cx,
421
 
            cy,
422
 
            i,
423
 
            diameter = radius * 2,
424
 
            currentArray,
425
 
            pathArrayLen;
426
 
        this._pathArray = this._pathArray || [];
427
 
        yRadius = yRadius || radius;
428
 
        if(this._pathType !== "M")
429
 
        {
430
 
            this._pathType = "M";
431
 
            currentArray = ["M"];
432
 
            this._pathArray.push(currentArray);
433
 
        }
434
 
        else
435
 
        {
436
 
            currentArray = this._getCurrentArray();
437
 
        }
438
 
        pathArrayLen = this._pathArray.length - 1;
439
 
        this._pathArray[pathArrayLen].push(x);
440
 
        this._pathArray[pathArrayLen].push(x);
441
 
 
442
 
        // limit sweep to reasonable numbers
443
 
        if(Math.abs(arc) > 360)
444
 
        {
445
 
            arc = 360;
446
 
        }
447
 
 
448
 
        // First we calculate how many segments are needed
449
 
        // for a smooth arc.
450
 
        segs = Math.ceil(Math.abs(arc) / 45);
451
 
 
452
 
        // Now calculate the sweep of each segment.
453
 
        segAngle = arc / segs;
454
 
 
455
 
        // The math requires radians rather than degrees. To convert from degrees
456
 
        // use the formula (degrees/180)*Math.PI to get radians.
457
 
        theta = -(segAngle / 180) * Math.PI;
458
 
 
459
 
        // convert angle startAngle to radians
460
 
        angle = (startAngle / 180) * Math.PI;
461
 
        if(segs > 0)
462
 
        {
463
 
            // draw a line from the center to the start of the curve
464
 
            ax = x + Math.cos(startAngle / 180 * Math.PI) * radius;
465
 
            ay = y + Math.sin(startAngle / 180 * Math.PI) * yRadius;
466
 
            this._pathType = "L";
467
 
            pathArrayLen++;
468
 
            this._pathArray[pathArrayLen] = ["L"];
469
 
            this._pathArray[pathArrayLen].push(Math.round(ax));
470
 
            this._pathArray[pathArrayLen].push(Math.round(ay));
471
 
            pathArrayLen++;
472
 
            this._pathType = "Q";
473
 
            this._pathArray[pathArrayLen] = ["Q"];
474
 
            for(i = 0; i < segs; ++i)
475
 
            {
476
 
                angle += theta;
477
 
                angleMid = angle - (theta / 2);
478
 
                bx = x + Math.cos(angle) * radius;
479
 
                by = y + Math.sin(angle) * yRadius;
480
 
                cx = x + Math.cos(angleMid) * (radius / Math.cos(theta / 2));
481
 
                cy = y + Math.sin(angleMid) * (yRadius / Math.cos(theta / 2));
482
 
                this._pathArray[pathArrayLen].push(Math.round(cx));
483
 
                this._pathArray[pathArrayLen].push(Math.round(cy));
484
 
                this._pathArray[pathArrayLen].push(Math.round(bx));
485
 
                this._pathArray[pathArrayLen].push(Math.round(by));
486
 
            }
487
 
        }
488
 
        this._currentX = x;
489
 
        this._currentY = y;
490
 
        this._trackSize(diameter, diameter);
491
 
        return this;
492
 
    },
493
 
 
494
 
    /**
495
 
     * Draws a line segment using the current line style from the current drawing position to the specified x and y coordinates.
496
 
     *
497
 
     * @method lineTo
498
 
     * @param {Number} point1 x-coordinate for the end point.
499
 
     * @param {Number} point2 y-coordinate for the end point.
500
 
     * @chainable
501
 
     */
502
 
    lineTo: function()
503
 
    {
504
 
        this._lineTo.apply(this, [Y.Array(arguments), false]);
505
 
        return this;
506
 
    },
507
 
 
508
 
    /**
509
 
     * Draws a line segment using the current line style from the current drawing position to the relative x and y coordinates.
510
 
     *
511
 
     * @method relativeLineTo
512
 
     * @param {Number} point1 x-coordinate for the end point.
513
 
     * @param {Number} point2 y-coordinate for the end point.
514
 
     * @chainable
515
 
     */
516
 
    relativeLineTo: function()
517
 
    {
518
 
        this._lineTo.apply(this, [Y.Array(arguments), true]);
519
 
        return this;
520
 
    },
521
 
 
522
 
    /**
523
 
     * Implements lineTo methods.
524
 
     *
525
 
     * @method _lineTo
526
 
     * @param {Array} args The arguments to be used.
527
 
     * @param {Boolean} relative Indicates whether or not to use relative coordinates.
528
 
     * @private
529
 
     */
530
 
    _lineTo: function(args, relative) {
531
 
        var point1 = args[0],
532
 
            i,
533
 
            len,
534
 
            pathArrayLen,
535
 
            currentArray,
536
 
            x,
537
 
            y,
538
 
            command = relative ? "l" : "L",
539
 
            relativeX = relative ? parseFloat(this._currentX) : 0,
540
 
            relativeY = relative ? parseFloat(this._currentY) : 0;
541
 
        this._pathArray = this._pathArray || [];
542
 
        this._shapeType = "path";
543
 
        len = args.length;
544
 
        if(this._pathType !== command)
545
 
        {
546
 
            this._pathType = command;
547
 
            currentArray = [command];
548
 
            this._pathArray.push(currentArray);
549
 
        }
550
 
        else
551
 
        {
552
 
            currentArray = this._getCurrentArray();
553
 
        }
554
 
        pathArrayLen = this._pathArray.length - 1;
555
 
        if (typeof point1 === 'string' || typeof point1 === 'number') {
556
 
            for (i = 0; i < len; i = i + 2) {
557
 
                x = parseFloat(args[i]);
558
 
                y = parseFloat(args[i + 1]);
559
 
                this._pathArray[pathArrayLen].push(x);
560
 
                this._pathArray[pathArrayLen].push(y);
561
 
                x = x + relativeX;
562
 
                y = y + relativeY;
563
 
                this._currentX = x;
564
 
                this._currentY = y;
565
 
                this._trackSize.apply(this, [x, y]);
566
 
            }
567
 
        }
568
 
        else
569
 
        {
570
 
            for (i = 0; i < len; ++i) {
571
 
                x = parseFloat(args[i][0]);
572
 
                y = parseFloat(args[i][1]);
573
 
                this._pathArray[pathArrayLen].push(x);
574
 
                this._pathArray[pathArrayLen].push(y);
575
 
                this._currentX = x;
576
 
                this._currentY = y;
577
 
                x = x + relativeX;
578
 
                y = y + relativeY;
579
 
                this._trackSize.apply(this, [x, y]);
580
 
            }
581
 
        }
582
 
    },
583
 
 
584
 
    /**
585
 
     * Moves the current drawing position to specified x and y coordinates.
586
 
     *
587
 
     * @method moveTo
588
 
     * @param {Number} x x-coordinate for the end point.
589
 
     * @param {Number} y y-coordinate for the end point.
590
 
     * @chainable
591
 
     */
592
 
    moveTo: function()
593
 
    {
594
 
        this._moveTo.apply(this, [Y.Array(arguments), false]);
595
 
        return this;
596
 
    },
597
 
 
598
 
    /**
599
 
     * Moves the current drawing position relative to specified x and y coordinates.
600
 
     *
601
 
     * @method relativeMoveTo
602
 
     * @param {Number} x x-coordinate for the end point.
603
 
     * @param {Number} y y-coordinate for the end point.
604
 
     * @chainable
605
 
     */
606
 
    relativeMoveTo: function()
607
 
    {
608
 
        this._moveTo.apply(this, [Y.Array(arguments), true]);
609
 
        return this;
610
 
    },
611
 
 
612
 
    /**
613
 
     * Implements moveTo methods.
614
 
     *
615
 
     * @method _moveTo
616
 
     * @param {Array} args The arguments to be used.
617
 
     * @param {Boolean} relative Indicates whether or not to use relative coordinates.
618
 
     * @private
619
 
     */
620
 
    _moveTo: function(args, relative) {
621
 
        var pathArrayLen,
622
 
            currentArray,
623
 
            x = parseFloat(args[0]),
624
 
            y = parseFloat(args[1]),
625
 
            command = relative ? "m" : "M",
626
 
            relativeX = relative ? parseFloat(this._currentX) : 0,
627
 
            relativeY = relative ? parseFloat(this._currentY) : 0;
628
 
        this._pathArray = this._pathArray || [];
629
 
        this._pathType = command;
630
 
        currentArray = [command];
631
 
        this._pathArray.push(currentArray);
632
 
        pathArrayLen = this._pathArray.length - 1;
633
 
        this._pathArray[pathArrayLen] = this._pathArray[pathArrayLen].concat([x, y]);
634
 
        x = x + relativeX;
635
 
        y = y + relativeY;
636
 
        this._currentX = x;
637
 
        this._currentY = y;
638
 
        this._trackSize(x, y);
639
 
    },
640
 
 
641
 
    /**
642
 
     * Completes a drawing operation.
643
 
     *
644
 
     * @method end
645
 
     * @chainable
646
 
     */
647
 
    end: function()
648
 
    {
649
 
        this._closePath();
650
 
        return this;
651
 
    },
652
 
 
653
 
    /**
654
 
     * Clears the path.
655
 
     *
656
 
     * @method clear
657
 
     * @chainable
658
 
     */
659
 
    clear: function()
660
 
    {
661
 
        this._currentX = 0;
662
 
        this._currentY = 0;
663
 
        this._width = 0;
664
 
        this._height = 0;
665
 
        this._left = 0;
666
 
        this._right = 0;
667
 
        this._top = 0;
668
 
        this._bottom = 0;
669
 
        this._pathArray = [];
670
 
        this._path = "";
671
 
        this._pathType = "";
672
 
        return this;
673
 
    },
674
 
 
675
 
    /**
676
 
     * Draws the path.
677
 
     *
678
 
     * @method _closePath
679
 
     * @private
680
 
     */
681
 
    _closePath: function()
682
 
    {
683
 
        var pathArray,
684
 
            segmentArray,
685
 
            pathType,
686
 
            len,
687
 
            val,
688
 
            i,
689
 
            path = "",
690
 
            node = this.node,
691
 
            left = parseFloat(this._left),
692
 
            top = parseFloat(this._top),
693
 
            fill = this.get("fill");
694
 
        if(this._pathArray)
695
 
        {
696
 
            pathArray = this._pathArray.concat();
697
 
            while(pathArray && pathArray.length > 0)
698
 
            {
699
 
                segmentArray = pathArray.shift();
700
 
                len = segmentArray.length;
701
 
                pathType = segmentArray[0];
702
 
                if(pathType === "A")
703
 
                {
704
 
                    path += pathType + segmentArray[1] + "," + segmentArray[2];
705
 
                }
706
 
                else if(pathType === "z" || pathType === "Z")
707
 
                {
708
 
                    path += " z ";
709
 
                }
710
 
                else if(pathType === "C" || pathType === "c")
711
 
                {
712
 
                    path += pathType + (segmentArray[1] - left)+ "," + (segmentArray[2] - top);
713
 
                }
714
 
                else
715
 
                {
716
 
                    path += " " + pathType + parseFloat(segmentArray[1] - left);
717
 
                }
718
 
                switch(pathType)
719
 
                {
720
 
                    case "L" :
721
 
                    case "l" :
722
 
                    case "M" :
723
 
                    case "m" :
724
 
                    case "Q" :
725
 
                    case "q" :
726
 
                        for(i = 2; i < len; ++i)
727
 
                        {
728
 
                            val = (i % 2 === 0) ? top : left;
729
 
                            val = segmentArray[i] - val;
730
 
                            path += ", " + parseFloat(val);
731
 
                        }
732
 
                    break;
733
 
                    case "A" :
734
 
                        val = " " + parseFloat(segmentArray[3]) + " " + parseFloat(segmentArray[4]);
735
 
                        val += "," + parseFloat(segmentArray[5]) + " " + parseFloat(segmentArray[6] - left);
736
 
                        val += "," + parseFloat(segmentArray[7] - top);
737
 
                        path += " " + val;
738
 
                    break;
739
 
                    case "C" :
740
 
                    case "c" :
741
 
                        for(i = 3; i < len - 1; i = i + 2)
742
 
                        {
743
 
                            val = parseFloat(segmentArray[i] - left);
744
 
                            val = val + ", ";
745
 
                            val = val + parseFloat(segmentArray[i + 1] - top);
746
 
                            path += " " + val;
747
 
                        }
748
 
                    break;
749
 
                }
750
 
            }
751
 
            if(fill && fill.color)
752
 
            {
753
 
                path += 'z';
754
 
            }
755
 
            Y.Lang.trim(path);
756
 
            if(path)
757
 
            {
758
 
                node.setAttribute("d", path);
759
 
            }
760
 
 
761
 
            this._path = path;
762
 
            this._fillChangeHandler();
763
 
            this._strokeChangeHandler();
764
 
            this._updateTransform();
765
 
        }
766
 
    },
767
 
 
768
 
    /**
769
 
     * Ends a fill and stroke
770
 
     *
771
 
     * @method closePath
772
 
     * @chainable
773
 
     */
774
 
    closePath: function()
775
 
    {
776
 
        this._pathArray.push(["z"]);
777
 
        return this;
778
 
    },
779
 
 
780
 
    /**
781
 
     * Returns the current array of drawing commands.
782
 
     *
783
 
     * @method _getCurrentArray
784
 
     * @return Array
785
 
     * @private
786
 
     */
787
 
    _getCurrentArray: function()
788
 
    {
789
 
        var currentArray = this._pathArray[Math.max(0, this._pathArray.length - 1)];
790
 
        if(!currentArray)
791
 
        {
792
 
            currentArray = [];
793
 
            this._pathArray.push(currentArray);
794
 
        }
795
 
        return currentArray;
796
 
    },
797
 
 
798
 
    /**
799
 
     * Returns the points on a curve
800
 
     *
801
 
     * @method getBezierData
802
 
     * @param Array points Array containing the begin, end and control points of a curve.
803
 
     * @param Number t The value for incrementing the next set of points.
804
 
     * @return Array
805
 
     * @private
806
 
     */
807
 
    getBezierData: function(points, t) {
808
 
        var n = points.length,
809
 
            tmp = [],
810
 
            i,
811
 
            j;
812
 
 
813
 
        for (i = 0; i < n; ++i){
814
 
            tmp[i] = [points[i][0], points[i][1]]; // save input
815
 
        }
816
 
 
817
 
        for (j = 1; j < n; ++j) {
818
 
            for (i = 0; i < n - j; ++i) {
819
 
                tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
820
 
                tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
821
 
            }
822
 
        }
823
 
        return [ tmp[0][0], tmp[0][1] ];
824
 
    },
825
 
 
826
 
    /**
827
 
     * Calculates the bounding box for a curve
828
 
     *
829
 
     * @method _setCurveBoundingBox
830
 
     * @param Array pts Array containing points for start, end and control points of a curve.
831
 
     * @param Number w Width used to calculate the number of points to describe the curve.
832
 
     * @param Number h Height used to calculate the number of points to describe the curve.
833
 
     * @private
834
 
     */
835
 
    _setCurveBoundingBox: function(pts, w, h)
836
 
    {
837
 
        var i,
838
 
            left = this._currentX,
839
 
            right = left,
840
 
            top = this._currentY,
841
 
            bottom = top,
842
 
            len = Math.round(Math.sqrt((w * w) + (h * h))),
843
 
            t = 1/len,
844
 
            xy;
845
 
        for(i = 0; i < len; ++i)
846
 
        {
847
 
            xy = this.getBezierData(pts, t * i);
848
 
            left = isNaN(left) ? xy[0] : Math.min(xy[0], left);
849
 
            right = isNaN(right) ? xy[0] : Math.max(xy[0], right);
850
 
            top = isNaN(top) ? xy[1] : Math.min(xy[1], top);
851
 
            bottom = isNaN(bottom) ? xy[1] : Math.max(xy[1], bottom);
852
 
        }
853
 
        left = Math.round(left * 10)/10;
854
 
        right = Math.round(right * 10)/10;
855
 
        top = Math.round(top * 10)/10;
856
 
        bottom = Math.round(bottom * 10)/10;
857
 
        this._trackSize(right, bottom);
858
 
        this._trackSize(left, top);
859
 
    },
860
 
 
861
 
    /**
862
 
     * Updates the size of the graphics object
863
 
     *
864
 
     * @method _trackSize
865
 
     * @param {Number} w width
866
 
     * @param {Number} h height
867
 
     * @private
868
 
     */
869
 
    _trackSize: function(w, h) {
870
 
        if (w > this._right) {
871
 
            this._right = w;
872
 
        }
873
 
        if(w < this._left)
874
 
        {
875
 
            this._left = w;
876
 
        }
877
 
        if (h < this._top)
878
 
        {
879
 
            this._top = h;
880
 
        }
881
 
        if (h > this._bottom)
882
 
        {
883
 
            this._bottom = h;
884
 
        }
885
 
        this._width = this._right - this._left;
886
 
        this._height = this._bottom - this._top;
887
 
    }
888
 
};
889
 
Y.SVGDrawing = SVGDrawing;
890
 
/**
891
 
 * <a href="http://www.w3.org/TR/SVG/">SVG</a> implementation of the <a href="Shape.html">`Shape`</a> class.
892
 
 * `SVGShape` is not intended to be used directly. Instead, use the <a href="Shape.html">`Shape`</a> class.
893
 
 * If the browser has <a href="http://www.w3.org/TR/SVG/">SVG</a> capabilities, the <a href="Shape.html">`Shape`</a>
894
 
 * class will point to the `SVGShape` class.
895
 
 *
896
 
 * @module graphics
897
 
 * @class SVGShape
898
 
 * @constructor
899
 
 * @param {Object} cfg (optional) Attribute configs
900
 
 */
901
 
SVGShape = function()
902
 
{
903
 
    this._transforms = [];
904
 
    this.matrix = new Y.Matrix();
905
 
    this._normalizedMatrix = new Y.Matrix();
906
 
    SVGShape.superclass.constructor.apply(this, arguments);
907
 
};
908
 
 
909
 
SVGShape.NAME = "shape";
910
 
 
911
 
Y.extend(SVGShape, Y.GraphicBase, Y.mix({
912
 
    /**
913
 
     * Storage for x attribute.
914
 
     *
915
 
     * @property _x
916
 
     * @protected
917
 
     */
918
 
    _x: 0,
919
 
 
920
 
    /**
921
 
     * Storage for y attribute.
922
 
     *
923
 
     * @property _y
924
 
     * @protected
925
 
     */
926
 
    _y: 0,
927
 
 
928
 
    /**
929
 
     * Init method, invoked during construction.
930
 
     * Calls `initializer` method.
931
 
     *
932
 
     * @method init
933
 
     * @protected
934
 
     */
935
 
        init: function()
936
 
        {
937
 
                this.initializer.apply(this, arguments);
938
 
        },
939
 
 
940
 
        /**
941
 
         * Initializes the shape
942
 
         *
943
 
         * @private
944
 
         * @method initializer
945
 
         */
946
 
        initializer: function(cfg)
947
 
        {
948
 
                var host = this,
949
 
            graphic = cfg.graphic,
950
 
            data = this.get("data");
951
 
                host.createNode();
952
 
                if(graphic)
953
 
        {
954
 
            host._setGraphic(graphic);
955
 
        }
956
 
        if(data)
957
 
        {
958
 
            host._parsePathData(data);
959
 
        }
960
 
        host._updateHandler();
961
 
        },
962
 
 
963
 
    /**
964
 
     * Set the Graphic instance for the shape.
965
 
     *
966
 
     * @method _setGraphic
967
 
     * @param {Graphic | Node | HTMLElement | String} render This param is used to determine the graphic instance. If it is a
968
 
     * `Graphic` instance, it will be assigned to the `graphic` attribute. Otherwise, a new Graphic instance will be created
969
 
     * and rendered into the dom element that the render represents.
970
 
     * @private
971
 
     */
972
 
    _setGraphic: function(render)
973
 
    {
974
 
        var graphic;
975
 
        if(render instanceof Y.SVGGraphic)
976
 
        {
977
 
            this._graphic = render;
978
 
        }
979
 
        else
980
 
        {
981
 
            render = Y.one(render);
982
 
            graphic = new Y.SVGGraphic({
983
 
                render: render
984
 
            });
985
 
            graphic._appendShape(this);
986
 
            this._graphic = graphic;
987
 
        }
988
 
    },
989
 
 
990
 
        /**
991
 
         * Add a class name to each node.
992
 
         *
993
 
         * @method addClass
994
 
         * @param {String} className the class name to add to the node's class attribute
995
 
         */
996
 
        addClass: function(className)
997
 
        {
998
 
        var node = this.node;
999
 
                node.className.baseVal = Y_LANG.trim([node.className.baseVal, className].join(' '));
1000
 
        },
1001
 
 
1002
 
        /**
1003
 
         * Removes a class name from each node.
1004
 
         *
1005
 
         * @method removeClass
1006
 
         * @param {String} className the class name to remove from the node's class attribute
1007
 
         */
1008
 
        removeClass: function(className)
1009
 
        {
1010
 
                var node = this.node,
1011
 
                        classString = node.className.baseVal;
1012
 
                classString = classString.replace(new RegExp(className + ' '), className).replace(new RegExp(className), '');
1013
 
                node.className.baseVal = classString;
1014
 
        },
1015
 
 
1016
 
        /**
1017
 
         * Gets the current position of the node in page coordinates.
1018
 
         *
1019
 
         * @method getXY
1020
 
         * @return Array The XY position of the shape.
1021
 
         */
1022
 
        getXY: function()
1023
 
        {
1024
 
                var graphic = this._graphic,
1025
 
                        parentXY = graphic.getXY(),
1026
 
                        x = this._x,
1027
 
                        y = this._y;
1028
 
                return [parentXY[0] + x, parentXY[1] + y];
1029
 
        },
1030
 
 
1031
 
        /**
1032
 
         * Set the position of the shape in page coordinates, regardless of how the node is positioned.
1033
 
         *
1034
 
         * @method setXY
1035
 
         * @param {Array} Contains x & y values for new position (coordinates are page-based)
1036
 
         */
1037
 
        setXY: function(xy)
1038
 
        {
1039
 
                var graphic = this._graphic,
1040
 
                        parentXY = graphic.getXY();
1041
 
                this._x = xy[0] - parentXY[0];
1042
 
                this._y = xy[1] - parentXY[1];
1043
 
        this.set("transform", this.get("transform"));
1044
 
        },
1045
 
 
1046
 
        /**
1047
 
         * Determines whether the node is an ancestor of another HTML element in the DOM hierarchy.
1048
 
         *
1049
 
         * @method contains
1050
 
         * @param {SVGShape | HTMLElement} needle The possible node or descendent
1051
 
         * @return Boolean Whether or not this shape is the needle or its ancestor.
1052
 
         */
1053
 
        contains: function(needle)
1054
 
        {
1055
 
                return needle === Y.one(this.node);
1056
 
        },
1057
 
 
1058
 
        /**
1059
 
         * Compares nodes to determine if they match.
1060
 
         * Node instances can be compared to each other and/or HTMLElements.
1061
 
         * @method compareTo
1062
 
         * @param {HTMLElement | Node} refNode The reference node to compare to the node.
1063
 
         * @return {Boolean} True if the nodes match, false if they do not.
1064
 
         */
1065
 
        compareTo: function(refNode) {
1066
 
                var node = this.node;
1067
 
 
1068
 
                return node === refNode;
1069
 
        },
1070
 
 
1071
 
        /**
1072
 
         * Test if the supplied node matches the supplied selector.
1073
 
         *
1074
 
         * @method test
1075
 
         * @param {String} selector The CSS selector to test against.
1076
 
         * @return Boolean Wheter or not the shape matches the selector.
1077
 
         */
1078
 
        test: function(selector)
1079
 
        {
1080
 
                return Y.Selector.test(this.node, selector);
1081
 
        },
1082
 
 
1083
 
        /**
1084
 
         * Value function for fill attribute
1085
 
         *
1086
 
         * @private
1087
 
         * @method _getDefaultFill
1088
 
         * @return Object
1089
 
         */
1090
 
        _getDefaultFill: function() {
1091
 
                return {
1092
 
                        type: "solid",
1093
 
                        opacity: 1,
1094
 
                        cx: 0.5,
1095
 
                        cy: 0.5,
1096
 
                        fx: 0.5,
1097
 
                        fy: 0.5,
1098
 
                        r: 0.5
1099
 
                };
1100
 
        },
1101
 
 
1102
 
        /**
1103
 
         * Value function for stroke attribute
1104
 
         *
1105
 
         * @private
1106
 
         * @method _getDefaultStroke
1107
 
         * @return Object
1108
 
         */
1109
 
        _getDefaultStroke: function()
1110
 
        {
1111
 
                return {
1112
 
                        weight: 1,
1113
 
                        dashstyle: "none",
1114
 
                        color: "#000",
1115
 
                        opacity: 1.0
1116
 
                };
1117
 
        },
1118
 
 
1119
 
        /**
1120
 
         * Creates the dom node for the shape.
1121
 
         *
1122
 
     * @method createNode
1123
 
         * @return HTMLElement
1124
 
         * @private
1125
 
         */
1126
 
        createNode: function()
1127
 
        {
1128
 
                var host = this,
1129
 
            node = DOCUMENT.createElementNS("http://www.w3.org/2000/svg", "svg:" + this._type),
1130
 
                        id = host.get("id"),
1131
 
            name = host.name,
1132
 
            concat = host._camelCaseConcat,
1133
 
                        pointerEvents = host.get("pointerEvents");
1134
 
                host.node = node;
1135
 
                host.addClass(
1136
 
            _getClassName(SHAPE) +
1137
 
            " " +
1138
 
            _getClassName(concat(IMPLEMENTATION, SHAPE)) +
1139
 
            " " +
1140
 
            _getClassName(name) +
1141
 
            " " +
1142
 
            _getClassName(concat(IMPLEMENTATION, name))
1143
 
        );
1144
 
        if(id)
1145
 
                {
1146
 
                        node.setAttribute("id", id);
1147
 
                }
1148
 
                if(pointerEvents)
1149
 
                {
1150
 
                        node.setAttribute("pointer-events", pointerEvents);
1151
 
                }
1152
 
        if(!host.get("visible"))
1153
 
        {
1154
 
            Y.one(node).setStyle("visibility", "hidden");
1155
 
        }
1156
 
        },
1157
 
 
1158
 
 
1159
 
        /**
1160
 
     * Overrides default `on` method. Checks to see if its a dom interaction event. If so,
1161
 
     * return an event attached to the `node` element. If not, return the normal functionality.
1162
 
     *
1163
 
     * @method on
1164
 
     * @param {String} type event type
1165
 
     * @param {Object} callback function
1166
 
         * @private
1167
 
         */
1168
 
        on: function(type, fn)
1169
 
        {
1170
 
                if(Y.Node.DOM_EVENTS[type])
1171
 
                {
1172
 
                        return Y.one("#" +  this.get("id")).on(type, fn);
1173
 
                }
1174
 
                return Y.on.apply(this, arguments);
1175
 
        },
1176
 
 
1177
 
        /**
1178
 
         * Adds a stroke to the shape node.
1179
 
         *
1180
 
         * @method _strokeChangeHandler
1181
 
         * @private
1182
 
         */
1183
 
        _strokeChangeHandler: function()
1184
 
        {
1185
 
                var node = this.node,
1186
 
                        stroke = this.get("stroke"),
1187
 
                        strokeOpacity,
1188
 
                        dashstyle,
1189
 
                        dash,
1190
 
                        linejoin;
1191
 
                if(stroke && stroke.weight && stroke.weight > 0)
1192
 
                {
1193
 
                        linejoin = stroke.linejoin || "round";
1194
 
                        strokeOpacity = parseFloat(stroke.opacity);
1195
 
                        dashstyle = stroke.dashstyle || "none";
1196
 
                        dash = Y_LANG.isArray(dashstyle) ? dashstyle.toString() : dashstyle;
1197
 
                        stroke.color = stroke.color || "#000000";
1198
 
                        stroke.weight = stroke.weight || 1;
1199
 
                        stroke.opacity = Y_LANG.isNumber(strokeOpacity) ? strokeOpacity : 1;
1200
 
                        stroke.linecap = stroke.linecap || "butt";
1201
 
                        node.setAttribute("stroke-dasharray", dash);
1202
 
                        node.setAttribute("stroke", stroke.color);
1203
 
                        node.setAttribute("stroke-linecap", stroke.linecap);
1204
 
                        node.setAttribute("stroke-width",  stroke.weight);
1205
 
                        node.setAttribute("stroke-opacity", stroke.opacity);
1206
 
                        if(linejoin === "round" || linejoin === "bevel")
1207
 
                        {
1208
 
                                node.setAttribute("stroke-linejoin", linejoin);
1209
 
                        }
1210
 
                        else
1211
 
                        {
1212
 
                                linejoin = parseInt(linejoin, 10);
1213
 
                                if(Y_LANG.isNumber(linejoin))
1214
 
                                {
1215
 
                                        node.setAttribute("stroke-miterlimit",  Math.max(linejoin, 1));
1216
 
                                        node.setAttribute("stroke-linejoin", "miter");
1217
 
                                }
1218
 
                        }
1219
 
                }
1220
 
                else
1221
 
                {
1222
 
                        node.setAttribute("stroke", "none");
1223
 
                }
1224
 
        },
1225
 
 
1226
 
        /**
1227
 
         * Adds a fill to the shape node.
1228
 
         *
1229
 
         * @method _fillChangeHandler
1230
 
         * @private
1231
 
         */
1232
 
        _fillChangeHandler: function()
1233
 
        {
1234
 
                var node = this.node,
1235
 
                        fill = this.get("fill"),
1236
 
                        fillOpacity,
1237
 
                        type;
1238
 
                if(fill)
1239
 
                {
1240
 
                        type = fill.type;
1241
 
                        if(type === "linear" || type === "radial")
1242
 
                        {
1243
 
                                this._setGradientFill(fill);
1244
 
                                node.setAttribute("fill", "url(#grad" + this.get("id") + ")");
1245
 
                        }
1246
 
                        else if(!fill.color)
1247
 
                        {
1248
 
                                node.setAttribute("fill", "none");
1249
 
                        }
1250
 
                        else
1251
 
                        {
1252
 
                fillOpacity = parseFloat(fill.opacity);
1253
 
                                fillOpacity = Y_LANG.isNumber(fillOpacity) ? fillOpacity : 1;
1254
 
                                node.setAttribute("fill", fill.color);
1255
 
                                node.setAttribute("fill-opacity", fillOpacity);
1256
 
                        }
1257
 
                }
1258
 
                else
1259
 
                {
1260
 
                        node.setAttribute("fill", "none");
1261
 
                }
1262
 
        },
1263
 
 
1264
 
        /**
1265
 
         * Creates a gradient fill
1266
 
         *
1267
 
         * @method _setGradientFill
1268
 
         * @param {String} type gradient type
1269
 
         * @private
1270
 
         */
1271
 
        _setGradientFill: function(fill) {
1272
 
                var offset,
1273
 
                        opacity,
1274
 
                        color,
1275
 
                        stopNode,
1276
 
            newStop,
1277
 
                        isNumber = Y_LANG.isNumber,
1278
 
                        graphic = this._graphic,
1279
 
                        type = fill.type,
1280
 
                        gradientNode = graphic.getGradientNode("grad" + this.get("id"), type),
1281
 
                        stops = fill.stops,
1282
 
                        w = this.get("width"),
1283
 
                        h = this.get("height"),
1284
 
                        rotation = fill.rotation || 0,
1285
 
                        radCon = Math.PI/180,
1286
 
            tanRadians = parseFloat(parseFloat(Math.tan(rotation * radCon)).toFixed(8)),
1287
 
            i,
1288
 
                        len,
1289
 
                        def,
1290
 
                        stop,
1291
 
                        x1 = "0%",
1292
 
                        x2 = "100%",
1293
 
                        y1 = "0%",
1294
 
                        y2 = "0%",
1295
 
                        cx = fill.cx,
1296
 
                        cy = fill.cy,
1297
 
                        fx = fill.fx,
1298
 
                        fy = fill.fy,
1299
 
                        r = fill.r,
1300
 
            stopNodes = [];
1301
 
                if(type === "linear")
1302
 
                {
1303
 
            cx = w/2;
1304
 
            cy = h/2;
1305
 
            if(Math.abs(tanRadians) * w/2 >= h/2)
1306
 
            {
1307
 
                if(rotation < 180)
1308
 
                {
1309
 
                    y1 = 0;
1310
 
                    y2 = h;
1311
 
                }
1312
 
                else
1313
 
                {
1314
 
                    y1 = h;
1315
 
                    y2 = 0;
1316
 
                }
1317
 
                x1 = cx - ((cy - y1)/tanRadians);
1318
 
                x2 = cx - ((cy - y2)/tanRadians);
1319
 
            }
1320
 
            else
1321
 
            {
1322
 
                if(rotation > 90 && rotation < 270)
1323
 
                {
1324
 
                    x1 = w;
1325
 
                    x2 = 0;
1326
 
                }
1327
 
                else
1328
 
                {
1329
 
                    x1 = 0;
1330
 
                    x2 = w;
1331
 
                }
1332
 
                y1 = ((tanRadians * (cx - x1)) - cy) * -1;
1333
 
                y2 = ((tanRadians * (cx - x2)) - cy) * -1;
1334
 
            }
1335
 
 
1336
 
            x1 = Math.round(100 * x1/w);
1337
 
            x2 = Math.round(100 * x2/w);
1338
 
            y1 = Math.round(100 * y1/h);
1339
 
            y2 = Math.round(100 * y2/h);
1340
 
 
1341
 
            //Set default value if not valid
1342
 
            x1 = isNumber(x1) ? x1 : 0;
1343
 
            x2 = isNumber(x2) ? x2 : 100;
1344
 
            y1 = isNumber(y1) ? y1 : 0;
1345
 
            y2 = isNumber(y2) ? y2 : 0;
1346
 
 
1347
 
            gradientNode.setAttribute("spreadMethod", "pad");
1348
 
                        gradientNode.setAttribute("width", w);
1349
 
                        gradientNode.setAttribute("height", h);
1350
 
            gradientNode.setAttribute("x1", x1 + "%");
1351
 
            gradientNode.setAttribute("x2", x2 + "%");
1352
 
            gradientNode.setAttribute("y1", y1 + "%");
1353
 
            gradientNode.setAttribute("y2", y2 + "%");
1354
 
                }
1355
 
                else
1356
 
                {
1357
 
                        gradientNode.setAttribute("cx", (cx * 100) + "%");
1358
 
                        gradientNode.setAttribute("cy", (cy * 100) + "%");
1359
 
                        gradientNode.setAttribute("fx", (fx * 100) + "%");
1360
 
                        gradientNode.setAttribute("fy", (fy * 100) + "%");
1361
 
                        gradientNode.setAttribute("r", (r * 100) + "%");
1362
 
                }
1363
 
 
1364
 
                len = stops.length;
1365
 
                def = 0;
1366
 
        for(i = 0; i < len; ++i)
1367
 
                {
1368
 
            if(this._stops && this._stops.length > 0)
1369
 
            {
1370
 
                stopNode = this._stops.shift();
1371
 
                newStop = false;
1372
 
            }
1373
 
            else
1374
 
            {
1375
 
                stopNode = graphic._createGraphicNode("stop");
1376
 
                newStop = true;
1377
 
            }
1378
 
                        stop = stops[i];
1379
 
                        opacity = stop.opacity;
1380
 
                        color = stop.color;
1381
 
                        offset = stop.offset || i/(len - 1);
1382
 
                        offset = Math.round(offset * 100) + "%";
1383
 
                        opacity = isNumber(opacity) ? opacity : 1;
1384
 
                        opacity = Math.max(0, Math.min(1, opacity));
1385
 
                        def = (i + 1) / len;
1386
 
                        stopNode.setAttribute("offset", offset);
1387
 
                        stopNode.setAttribute("stop-color", color);
1388
 
                        stopNode.setAttribute("stop-opacity", opacity);
1389
 
                        if(newStop)
1390
 
            {
1391
 
                gradientNode.appendChild(stopNode);
1392
 
            }
1393
 
            stopNodes.push(stopNode);
1394
 
                }
1395
 
        while(this._stops && this._stops.length > 0)
1396
 
        {
1397
 
            gradientNode.removeChild(this._stops.shift());
1398
 
        }
1399
 
        this._stops = stopNodes;
1400
 
        },
1401
 
 
1402
 
    _stops: null,
1403
 
 
1404
 
    /**
1405
 
     * Sets the value of an attribute.
1406
 
     *
1407
 
     * @method set
1408
 
     * @param {String|Object} name The name of the attribute. Alternatively, an object of key value pairs can
1409
 
     * be passed in to set multiple attributes at once.
1410
 
     * @param {Any} value The value to set the attribute to. This value is ignored if an object is received as
1411
 
     * the name param.
1412
 
     */
1413
 
        set: function()
1414
 
        {
1415
 
                var host = this;
1416
 
                AttributeLite.prototype.set.apply(host, arguments);
1417
 
                if(host.initialized)
1418
 
                {
1419
 
                        host._updateHandler();
1420
 
                }
1421
 
        },
1422
 
 
1423
 
        /**
1424
 
         * Specifies a 2d translation.
1425
 
         *
1426
 
         * @method translate
1427
 
         * @param {Number} x The value to transate on the x-axis.
1428
 
         * @param {Number} y The value to translate on the y-axis.
1429
 
         */
1430
 
        translate: function()
1431
 
        {
1432
 
                this._addTransform("translate", arguments);
1433
 
        },
1434
 
 
1435
 
        /**
1436
 
         * Translates the shape along the x-axis. When translating x and y coordinates,
1437
 
         * use the `translate` method.
1438
 
         *
1439
 
         * @method translateX
1440
 
         * @param {Number} x The value to translate.
1441
 
         */
1442
 
        translateX: function()
1443
 
    {
1444
 
        this._addTransform("translateX", arguments);
1445
 
    },
1446
 
 
1447
 
        /**
1448
 
         * Translates the shape along the y-axis. When translating x and y coordinates,
1449
 
         * use the `translate` method.
1450
 
         *
1451
 
         * @method translateY
1452
 
         * @param {Number} y The value to translate.
1453
 
         */
1454
 
        translateY: function()
1455
 
    {
1456
 
        this._addTransform("translateY", arguments);
1457
 
    },
1458
 
 
1459
 
    /**
1460
 
     * Skews the shape around the x-axis and y-axis.
1461
 
     *
1462
 
     * @method skew
1463
 
     * @param {Number} x The value to skew on the x-axis.
1464
 
     * @param {Number} y The value to skew on the y-axis.
1465
 
     */
1466
 
    skew: function()
1467
 
    {
1468
 
        this._addTransform("skew", arguments);
1469
 
    },
1470
 
 
1471
 
        /**
1472
 
         * Skews the shape around the x-axis.
1473
 
         *
1474
 
         * @method skewX
1475
 
         * @param {Number} x x-coordinate
1476
 
         */
1477
 
    skewX: function()
1478
 
    {
1479
 
        this._addTransform("skewX", arguments);
1480
 
    },
1481
 
 
1482
 
        /**
1483
 
         * Skews the shape around the y-axis.
1484
 
         *
1485
 
         * @method skewY
1486
 
         * @param {Number} y y-coordinate
1487
 
         */
1488
 
    skewY: function()
1489
 
    {
1490
 
        this._addTransform("skewY", arguments);
1491
 
    },
1492
 
 
1493
 
        /**
1494
 
         * Rotates the shape clockwise around it transformOrigin.
1495
 
         *
1496
 
         * @method rotate
1497
 
         * @param {Number} deg The degree of the rotation.
1498
 
         */
1499
 
    rotate: function()
1500
 
    {
1501
 
        this._addTransform("rotate", arguments);
1502
 
    },
1503
 
 
1504
 
        /**
1505
 
         * Specifies a 2d scaling operation.
1506
 
         *
1507
 
         * @method scale
1508
 
         * @param {Number} val
1509
 
         */
1510
 
    scale: function()
1511
 
    {
1512
 
        this._addTransform("scale", arguments);
1513
 
    },
1514
 
 
1515
 
    /**
1516
 
     * Adds a transform to the shape.
1517
 
     *
1518
 
     * @method _addTransform
1519
 
     * @param {String} type The transform being applied.
1520
 
     * @param {Array} args The arguments for the transform.
1521
 
         * @private
1522
 
         */
1523
 
        _addTransform: function(type, args)
1524
 
        {
1525
 
        args = Y.Array(args);
1526
 
        this._transform = Y_LANG.trim(this._transform + " " + type + "(" + args.join(", ") + ")");
1527
 
        args.unshift(type);
1528
 
        this._transforms.push(args);
1529
 
        if(this.initialized)
1530
 
        {
1531
 
            this._updateTransform();
1532
 
        }
1533
 
        },
1534
 
 
1535
 
        /**
1536
 
     * Applies all transforms.
1537
 
     *
1538
 
     * @method _updateTransform
1539
 
         * @private
1540
 
         */
1541
 
        _updateTransform: function()
1542
 
        {
1543
 
                var isPath = this._type === "path",
1544
 
            node = this.node,
1545
 
                        key,
1546
 
                        transform,
1547
 
                        transformOrigin,
1548
 
                        x,
1549
 
                        y,
1550
 
            tx,
1551
 
            ty,
1552
 
            matrix = this.matrix,
1553
 
            normalizedMatrix = this._normalizedMatrix,
1554
 
            i,
1555
 
            len = this._transforms.length;
1556
 
 
1557
 
        if(isPath || (this._transforms && this._transforms.length > 0))
1558
 
                {
1559
 
            x = this._x;
1560
 
            y = this._y;
1561
 
            transformOrigin = this.get("transformOrigin");
1562
 
            tx = x + (transformOrigin[0] * this.get("width"));
1563
 
            ty = y + (transformOrigin[1] * this.get("height"));
1564
 
            //need to use translate for x/y coords
1565
 
            if(isPath)
1566
 
            {
1567
 
                //adjust origin for custom shapes
1568
 
                if(!(this instanceof Y.SVGPath))
1569
 
                {
1570
 
                    tx = this._left + (transformOrigin[0] * this.get("width"));
1571
 
                    ty = this._top + (transformOrigin[1] * this.get("height"));
1572
 
                }
1573
 
                normalizedMatrix.init({dx: x + this._left, dy: y + this._top});
1574
 
            }
1575
 
            normalizedMatrix.translate(tx, ty);
1576
 
            for(i = 0; i < len; ++i)
1577
 
            {
1578
 
                key = this._transforms[i].shift();
1579
 
                if(key)
1580
 
                {
1581
 
                    normalizedMatrix[key].apply(normalizedMatrix, this._transforms[i]);
1582
 
                    matrix[key].apply(matrix, this._transforms[i]);
1583
 
                }
1584
 
                if(isPath)
1585
 
                {
1586
 
                    this._transforms[i].unshift(key);
1587
 
                }
1588
 
                        }
1589
 
            normalizedMatrix.translate(-tx, -ty);
1590
 
            transform = "matrix(" + normalizedMatrix.a + "," +
1591
 
                            normalizedMatrix.b + "," +
1592
 
                            normalizedMatrix.c + "," +
1593
 
                            normalizedMatrix.d + "," +
1594
 
                            normalizedMatrix.dx + "," +
1595
 
                            normalizedMatrix.dy + ")";
1596
 
                }
1597
 
        this._graphic.addToRedrawQueue(this);
1598
 
        if(transform)
1599
 
                {
1600
 
            node.setAttribute("transform", transform);
1601
 
        }
1602
 
        if(!isPath)
1603
 
        {
1604
 
            this._transforms = [];
1605
 
        }
1606
 
        },
1607
 
 
1608
 
        /**
1609
 
         * Draws the shape.
1610
 
         *
1611
 
         * @method _draw
1612
 
         * @private
1613
 
         */
1614
 
        _draw: function()
1615
 
        {
1616
 
                var node = this.node;
1617
 
                node.setAttribute("width", this.get("width"));
1618
 
                node.setAttribute("height", this.get("height"));
1619
 
                node.setAttribute("x", this._x);
1620
 
                node.setAttribute("y", this._y);
1621
 
                node.style.left = this._x + "px";
1622
 
                node.style.top = this._y + "px";
1623
 
                this._fillChangeHandler();
1624
 
                this._strokeChangeHandler();
1625
 
                this._updateTransform();
1626
 
        },
1627
 
 
1628
 
        /**
1629
 
     * Updates `Shape` based on attribute changes.
1630
 
     *
1631
 
     * @method _updateHandler
1632
 
         * @private
1633
 
         */
1634
 
        _updateHandler: function()
1635
 
        {
1636
 
                this._draw();
1637
 
        },
1638
 
 
1639
 
    /**
1640
 
     * Storage for the transform attribute.
1641
 
     *
1642
 
     * @property _transform
1643
 
     * @type String
1644
 
     * @private
1645
 
     */
1646
 
    _transform: "",
1647
 
 
1648
 
        /**
1649
 
         * Returns the bounds for a shape.
1650
 
         *
1651
 
     * Calculates the a new bounding box from the original corner coordinates (base on size and position) and the transform matrix.
1652
 
     * The calculated bounding box is used by the graphic instance to calculate its viewBox.
1653
 
     *
1654
 
         * @method getBounds
1655
 
         * @return Object
1656
 
         */
1657
 
        getBounds: function()
1658
 
        {
1659
 
                var type = this._type,
1660
 
                        stroke = this.get("stroke"),
1661
 
            w = this.get("width"),
1662
 
                        h = this.get("height"),
1663
 
                        x = type === "path" ? 0 : this._x,
1664
 
                        y = type === "path" ? 0 : this._y,
1665
 
            wt = 0;
1666
 
        if(type !== "path")
1667
 
        {
1668
 
            if(stroke && stroke.weight)
1669
 
            {
1670
 
                wt = stroke.weight;
1671
 
            }
1672
 
            w = (x + w + wt) - (x - wt);
1673
 
            h = (y + h + wt) - (y - wt);
1674
 
            x -= wt;
1675
 
            y -= wt;
1676
 
        }
1677
 
                return this._normalizedMatrix.getContentRect(w, h, x, y);
1678
 
        },
1679
 
 
1680
 
    /**
1681
 
     * Places the shape above all other shapes.
1682
 
     *
1683
 
     * @method toFront
1684
 
     */
1685
 
    toFront: function()
1686
 
    {
1687
 
        var graphic = this.get("graphic");
1688
 
        if(graphic)
1689
 
        {
1690
 
            graphic._toFront(this);
1691
 
        }
1692
 
    },
1693
 
 
1694
 
    /**
1695
 
     * Places the shape underneath all other shapes.
1696
 
     *
1697
 
     * @method toFront
1698
 
     */
1699
 
    toBack: function()
1700
 
    {
1701
 
        var graphic = this.get("graphic");
1702
 
        if(graphic)
1703
 
        {
1704
 
            graphic._toBack(this);
1705
 
        }
1706
 
    },
1707
 
 
1708
 
    /**
1709
 
     * Parses path data string and call mapped methods.
1710
 
     *
1711
 
     * @method _parsePathData
1712
 
     * @param {String} val The path data
1713
 
     * @private
1714
 
     */
1715
 
    _parsePathData: function(val)
1716
 
    {
1717
 
        var method,
1718
 
            methodSymbol,
1719
 
            args,
1720
 
            commandArray = Y.Lang.trim(val.match(SPLITPATHPATTERN)),
1721
 
            i,
1722
 
            len,
1723
 
            str,
1724
 
            symbolToMethod = this._pathSymbolToMethod;
1725
 
        if(commandArray)
1726
 
        {
1727
 
            this.clear();
1728
 
            len = commandArray.length || 0;
1729
 
            for(i = 0; i < len; i = i + 1)
1730
 
            {
1731
 
                str = commandArray[i];
1732
 
                methodSymbol = str.substr(0, 1);
1733
 
                args = str.substr(1).match(SPLITARGSPATTERN);
1734
 
                method = symbolToMethod[methodSymbol];
1735
 
                if(method)
1736
 
                {
1737
 
                    if(args)
1738
 
                    {
1739
 
                        this[method].apply(this, args);
1740
 
                    }
1741
 
                    else
1742
 
                    {
1743
 
                        this[method].apply(this);
1744
 
                    }
1745
 
                }
1746
 
            }
1747
 
            this.end();
1748
 
        }
1749
 
    },
1750
 
 
1751
 
    /**
1752
 
     * Destroys the shape instance.
1753
 
     *
1754
 
     * @method destroy
1755
 
     */
1756
 
    destroy: function()
1757
 
    {
1758
 
        var graphic = this.get("graphic");
1759
 
        if(graphic)
1760
 
        {
1761
 
            graphic.removeShape(this);
1762
 
        }
1763
 
        else
1764
 
        {
1765
 
            this._destroy();
1766
 
        }
1767
 
    },
1768
 
 
1769
 
    /**
1770
 
     *  Implementation for shape destruction
1771
 
     *
1772
 
     *  @method destroy
1773
 
     *  @protected
1774
 
     */
1775
 
    _destroy: function()
1776
 
    {
1777
 
        if(this.node)
1778
 
        {
1779
 
            Y.Event.purgeElement(this.node, true);
1780
 
            if(this.node.parentNode)
1781
 
            {
1782
 
                this.node.parentNode.removeChild(this.node);
1783
 
            }
1784
 
            this.node = null;
1785
 
        }
1786
 
    }
1787
 
 }, Y.SVGDrawing.prototype));
1788
 
 
1789
 
SVGShape.ATTRS = {
1790
 
        /**
1791
 
         * 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
1792
 
         * fraction of the shape's corresponding bounding box dimension. The default value is [0.5, 0.5].
1793
 
         *
1794
 
         * @config transformOrigin
1795
 
         * @type Array
1796
 
         */
1797
 
        transformOrigin: {
1798
 
                valueFn: function()
1799
 
                {
1800
 
                        return [0.5, 0.5];
1801
 
                }
1802
 
        },
1803
 
 
1804
 
    /**
1805
 
     * <p>A string containing, in order, transform operations applied to the shape instance. The `transform` string can contain the following values:
1806
 
     *
1807
 
     *    <dl>
1808
 
     *        <dt>rotate</dt><dd>Rotates the shape clockwise around it transformOrigin.</dd>
1809
 
     *        <dt>translate</dt><dd>Specifies a 2d translation.</dd>
1810
 
     *        <dt>skew</dt><dd>Skews the shape around the x-axis and y-axis.</dd>
1811
 
     *        <dt>scale</dt><dd>Specifies a 2d scaling operation.</dd>
1812
 
     *        <dt>translateX</dt><dd>Translates the shape along the x-axis.</dd>
1813
 
     *        <dt>translateY</dt><dd>Translates the shape along the y-axis.</dd>
1814
 
     *        <dt>skewX</dt><dd>Skews the shape around the x-axis.</dd>
1815
 
     *        <dt>skewY</dt><dd>Skews the shape around the y-axis.</dd>
1816
 
     *        <dt>matrix</dt><dd>Specifies a 2D transformation matrix comprised of the specified six values.</dd>
1817
 
     *    </dl>
1818
 
     * </p>
1819
 
     * <p>Applying transforms through the transform attribute will reset the transform matrix and apply a new transform. The shape class also contains
1820
 
     * corresponding methods for each transform that will apply the transform to the current matrix. The below code illustrates how you might use the
1821
 
     * `transform` attribute to instantiate a recangle with a rotation of 45 degrees.</p>
1822
 
            var myRect = new Y.Rect({
1823
 
                type:"rect",
1824
 
                width: 50,
1825
 
                height: 40,
1826
 
                transform: "rotate(45)"
1827
 
            };
1828
 
     * <p>The code below would apply `translate` and `rotate` to an existing shape.</p>
1829
 
 
1830
 
        myRect.set("transform", "translate(40, 50) rotate(45)");
1831
 
         * @config transform
1832
 
     * @type String
1833
 
         */
1834
 
        transform: {
1835
 
                setter: function(val)
1836
 
        {
1837
 
            this.matrix.init();
1838
 
            this._normalizedMatrix.init();
1839
 
            this._transforms = this.matrix.getTransformArray(val);
1840
 
            this._transform = val;
1841
 
            return val;
1842
 
                },
1843
 
 
1844
 
        getter: function()
1845
 
        {
1846
 
            return this._transform;
1847
 
        }
1848
 
        },
1849
 
 
1850
 
        /**
1851
 
         * Unique id for class instance.
1852
 
         *
1853
 
         * @config id
1854
 
         * @type String
1855
 
         */
1856
 
        id: {
1857
 
                valueFn: function()
1858
 
                {
1859
 
                        return Y.guid();
1860
 
                },
1861
 
 
1862
 
                setter: function(val)
1863
 
                {
1864
 
                        var node = this.node;
1865
 
                        if(node)
1866
 
                        {
1867
 
                                node.setAttribute("id", val);
1868
 
                        }
1869
 
                        return val;
1870
 
                }
1871
 
        },
1872
 
 
1873
 
        /**
1874
 
         * Indicates the x position of shape.
1875
 
         *
1876
 
         * @config x
1877
 
         * @type Number
1878
 
         */
1879
 
        x: {
1880
 
        getter: function()
1881
 
        {
1882
 
            return this._x;
1883
 
        },
1884
 
 
1885
 
        setter: function(val)
1886
 
        {
1887
 
            var transform = this.get("transform");
1888
 
            this._x = val;
1889
 
            if(transform)
1890
 
            {
1891
 
                this.set("transform", transform);
1892
 
            }
1893
 
        }
1894
 
        },
1895
 
 
1896
 
        /**
1897
 
         * Indicates the y position of shape.
1898
 
         *
1899
 
         * @config y
1900
 
         * @type Number
1901
 
         */
1902
 
        y: {
1903
 
        getter: function()
1904
 
        {
1905
 
            return this._y;
1906
 
        },
1907
 
 
1908
 
        setter: function(val)
1909
 
        {
1910
 
            var transform = this.get("transform");
1911
 
            this._y = val;
1912
 
            if(transform)
1913
 
            {
1914
 
                this.set("transform", transform);
1915
 
            }
1916
 
        }
1917
 
        },
1918
 
 
1919
 
        /**
1920
 
         * Indicates the width of the shape
1921
 
         *
1922
 
         * @config width
1923
 
         * @type Number
1924
 
         */
1925
 
        width: {
1926
 
        value: 0
1927
 
    },
1928
 
 
1929
 
        /**
1930
 
         * Indicates the height of the shape
1931
 
         *
1932
 
         * @config height
1933
 
         * @type Number
1934
 
         */
1935
 
        height: {
1936
 
        value: 0
1937
 
    },
1938
 
 
1939
 
        /**
1940
 
         * Indicates whether the shape is visible.
1941
 
         *
1942
 
         * @config visible
1943
 
         * @type Boolean
1944
 
         */
1945
 
        visible: {
1946
 
                value: true,
1947
 
 
1948
 
                setter: function(val){
1949
 
                        var visibility = val ? "visible" : "hidden";
1950
 
                        if(this.node)
1951
 
            {
1952
 
                this.node.style.visibility = visibility;
1953
 
            }
1954
 
                        return val;
1955
 
                }
1956
 
        },
1957
 
 
1958
 
        /**
1959
 
         * Contains information about the fill of the shape.
1960
 
     *  <dl>
1961
 
     *      <dt>color</dt><dd>The color of the fill.</dd>
1962
 
     *      <dt>opacity</dt><dd>Number between 0 and 1 that indicates the opacity of the fill. The default value is 1.</dd>
1963
 
     *      <dt>type</dt><dd>Type of fill.
1964
 
     *          <dl>
1965
 
     *              <dt>solid</dt><dd>Solid single color fill. (default)</dd>
1966
 
     *              <dt>linear</dt><dd>Linear gradient fill.</dd>
1967
 
     *              <dt>radial</dt><dd>Radial gradient fill.</dd>
1968
 
     *          </dl>
1969
 
     *      </dd>
1970
 
     *  </dl>
1971
 
     *  <p>If a `linear` or `radial` is specified as the fill type. The following additional property is used:
1972
 
     *  <dl>
1973
 
     *      <dt>stops</dt><dd>An array of objects containing the following properties:
1974
 
     *          <dl>
1975
 
     *              <dt>color</dt><dd>The color of the stop.</dd>
1976
 
     *              <dt>opacity</dt><dd>Number between 0 and 1 that indicates the opacity of the stop. The default value is 1.
1977
 
     *              Note: No effect for IE 6 - 8</dd>
1978
 
     *              <dt>offset</dt><dd>Number between 0 and 1 indicating where the color stop is positioned.</dd>
1979
 
     *          </dl>
1980
 
     *      </dd>
1981
 
     *      <p>Linear gradients also have the following property:</p>
1982
 
     *      <dt>rotation</dt><dd>Linear gradients flow left to right by default. The rotation property allows you to change the
1983
 
     *      flow by rotation. (e.g. A rotation of 180 would make the gradient pain from right to left.)</dd>
1984
 
     *      <p>Radial gradients have the following additional properties:</p>
1985
 
     *      <dt>r</dt><dd>Radius of the gradient circle.</dd>
1986
 
     *      <dt>fx</dt><dd>Focal point x-coordinate of the gradient.</dd>
1987
 
     *      <dt>fy</dt><dd>Focal point y-coordinate of the gradient.</dd>
1988
 
     *      <dt>cx</dt><dd>
1989
 
     *          <p>The x-coordinate of the center of the gradient circle. Determines where the color stop begins. The default value 0.5.</p>
1990
 
     *          <p><strong>Note: </strong>Currently, this property is not implemented for corresponding `CanvasShape` and
1991
 
     *          `VMLShape` classes which are used on Android or IE 6 - 8.</p>
1992
 
     *      </dd>
1993
 
     *      <dt>cy</dt><dd>
1994
 
     *          <p>The y-coordinate of the center of the gradient circle. Determines where the color stop begins. The default value 0.5.</p>
1995
 
     *          <p><strong>Note: </strong>Currently, this property is not implemented for corresponding `CanvasShape` and `VMLShape`
1996
 
     *          classes which are used on Android or IE 6 - 8.</p>
1997
 
     *      </dd>
1998
 
     *  </dl>
1999
 
         *
2000
 
         * @config fill
2001
 
         * @type Object
2002
 
         */
2003
 
        fill: {
2004
 
                valueFn: "_getDefaultFill",
2005
 
 
2006
 
                setter: function(val)
2007
 
                {
2008
 
                        var fill,
2009
 
                                tmpl = this.get("fill") || this._getDefaultFill();
2010
 
                        fill = (val) ? Y.merge(tmpl, val) : null;
2011
 
                        if(fill && fill.color)
2012
 
                        {
2013
 
                                if(fill.color === undefined || fill.color === "none")
2014
 
                                {
2015
 
                                        fill.color = null;
2016
 
                                }
2017
 
                        }
2018
 
                        return fill;
2019
 
                }
2020
 
        },
2021
 
 
2022
 
        /**
2023
 
         * Contains information about the stroke of the shape.
2024
 
     *  <dl>
2025
 
     *      <dt>color</dt><dd>The color of the stroke.</dd>
2026
 
     *      <dt>weight</dt><dd>Number that indicates the width of the stroke.</dd>
2027
 
     *      <dt>opacity</dt><dd>Number between 0 and 1 that indicates the opacity of the stroke. The default value is 1.</dd>
2028
 
     *      <dt>dashstyle</dt>Indicates whether to draw a dashed stroke. When set to "none", a solid stroke is drawn. When set
2029
 
     *      to an array, the first index indicates the length of the dash. The second index indicates the length of gap.
2030
 
     *      <dt>linecap</dt><dd>Specifies the linecap for the stroke. The following values can be specified:
2031
 
     *          <dl>
2032
 
     *              <dt>butt (default)</dt><dd>Specifies a butt linecap.</dd>
2033
 
     *              <dt>square</dt><dd>Specifies a sqare linecap.</dd>
2034
 
     *              <dt>round</dt><dd>Specifies a round linecap.</dd>
2035
 
     *          </dl>
2036
 
     *      </dd>
2037
 
     *      <dt>linejoin</dt><dd>Specifies a linejoin for the stroke. The following values can be specified:
2038
 
     *          <dl>
2039
 
     *              <dt>round (default)</dt><dd>Specifies that the linejoin will be round.</dd>
2040
 
     *              <dt>bevel</dt><dd>Specifies a bevel for the linejoin.</dd>
2041
 
     *              <dt>miter limit</dt><dd>An integer specifying the miter limit of a miter linejoin. If you want to specify a linejoin
2042
 
     *              of miter, you simply specify the limit as opposed to having separate miter and miter limit values.</dd>
2043
 
     *          </dl>
2044
 
     *      </dd>
2045
 
     *  </dl>
2046
 
         *
2047
 
         * @config stroke
2048
 
         * @type Object
2049
 
         */
2050
 
        stroke: {
2051
 
                valueFn: "_getDefaultStroke",
2052
 
 
2053
 
                setter: function(val)
2054
 
                {
2055
 
                        var tmpl = this.get("stroke") || this._getDefaultStroke(),
2056
 
                wt;
2057
 
            if(val && val.hasOwnProperty("weight"))
2058
 
            {
2059
 
                wt = parseInt(val.weight, 10);
2060
 
                if(!isNaN(wt))
2061
 
                {
2062
 
                    val.weight = wt;
2063
 
                }
2064
 
            }
2065
 
            return (val) ? Y.merge(tmpl, val) : null;
2066
 
                }
2067
 
        },
2068
 
 
2069
 
        // Only implemented in SVG
2070
 
        // Determines whether the instance will receive mouse events.
2071
 
        //
2072
 
        // @config pointerEvents
2073
 
        // @type string
2074
 
        //
2075
 
        pointerEvents: {
2076
 
                valueFn: function()
2077
 
                {
2078
 
                        var val = "visiblePainted",
2079
 
                                node = this.node;
2080
 
                        if(node)
2081
 
                        {
2082
 
                                node.setAttribute("pointer-events", val);
2083
 
                        }
2084
 
                        return val;
2085
 
                },
2086
 
 
2087
 
                setter: function(val)
2088
 
                {
2089
 
                        var node = this.node;
2090
 
                        if(node)
2091
 
                        {
2092
 
                                node.setAttribute("pointer-events", val);
2093
 
                        }
2094
 
                        return val;
2095
 
                }
2096
 
        },
2097
 
 
2098
 
        /**
2099
 
         * Dom node for the shape.
2100
 
         *
2101
 
         * @config node
2102
 
         * @type HTMLElement
2103
 
         * @readOnly
2104
 
         */
2105
 
        node: {
2106
 
                readOnly: true,
2107
 
 
2108
 
        getter: function()
2109
 
        {
2110
 
            return this.node;
2111
 
        }
2112
 
        },
2113
 
 
2114
 
    /**
2115
 
     * Represents an SVG Path string. This will be parsed and added to shape's API to represent the SVG data across all
2116
 
     * implementations. Note that when using VML or SVG implementations, part of this content will be added to the DOM using
2117
 
     * respective VML/SVG attributes. If your content comes from an untrusted source, you will need to ensure that no
2118
 
     * malicious code is included in that content.
2119
 
     *
2120
 
     * @config data
2121
 
     * @type String
2122
 
     */
2123
 
    data: {
2124
 
        setter: function(val)
2125
 
        {
2126
 
            if(this.get("node"))
2127
 
            {
2128
 
                this._parsePathData(val);
2129
 
            }
2130
 
            return val;
2131
 
        }
2132
 
    },
2133
 
 
2134
 
        /**
2135
 
         * Reference to the parent graphic instance
2136
 
         *
2137
 
         * @config graphic
2138
 
         * @type SVGGraphic
2139
 
         * @readOnly
2140
 
         */
2141
 
        graphic: {
2142
 
                readOnly: true,
2143
 
 
2144
 
        getter: function()
2145
 
        {
2146
 
            return this._graphic;
2147
 
        }
2148
 
        }
2149
 
};
2150
 
Y.SVGShape = SVGShape;
2151
 
 
2152
 
/**
2153
 
 * <a href="http://www.w3.org/TR/SVG/">SVG</a> implementation of the <a href="Path.html">`Path`</a> class.
2154
 
 * `SVGPath` is not intended to be used directly. Instead, use the <a href="Path.html">`Path`</a> class.
2155
 
 * If the browser has <a href="http://www.w3.org/TR/SVG/">SVG</a> capabilities, the <a href="Path.html">`Path`</a>
2156
 
 * class will point to the `SVGPath` class.
2157
 
 *
2158
 
 * @module graphics
2159
 
 * @class SVGPath
2160
 
 * @extends SVGShape
2161
 
 * @constructor
2162
 
 */
2163
 
SVGPath = function()
2164
 
{
2165
 
        SVGPath.superclass.constructor.apply(this, arguments);
2166
 
};
2167
 
SVGPath.NAME = "path";
2168
 
Y.extend(SVGPath, Y.SVGShape, {
2169
 
    /**
2170
 
     * Left edge of the path
2171
 
     *
2172
 
     * @property _left
2173
 
     * @type Number
2174
 
     * @private
2175
 
     */
2176
 
    _left: 0,
2177
 
 
2178
 
    /**
2179
 
     * Right edge of the path
2180
 
     *
2181
 
     * @property _right
2182
 
     * @type Number
2183
 
     * @private
2184
 
     */
2185
 
    _right: 0,
2186
 
 
2187
 
    /**
2188
 
     * Top edge of the path
2189
 
     *
2190
 
     * @property _top
2191
 
     * @type Number
2192
 
     * @private
2193
 
     */
2194
 
    _top: 0,
2195
 
 
2196
 
    /**
2197
 
     * Bottom edge of the path
2198
 
     *
2199
 
     * @property _bottom
2200
 
     * @type Number
2201
 
     * @private
2202
 
     */
2203
 
    _bottom: 0,
2204
 
 
2205
 
    /**
2206
 
     * Indicates the type of shape
2207
 
     *
2208
 
     * @property _type
2209
 
     * @readOnly
2210
 
     * @type String
2211
 
     * @private
2212
 
     */
2213
 
    _type: "path",
2214
 
 
2215
 
    /**
2216
 
     * Storage for path
2217
 
     *
2218
 
     * @property _path
2219
 
     * @type String
2220
 
     * @private
2221
 
     */
2222
 
        _path: ""
2223
 
});
2224
 
 
2225
 
SVGPath.ATTRS = Y.merge(Y.SVGShape.ATTRS, {
2226
 
        /**
2227
 
         * Indicates the path used for the node.
2228
 
         *
2229
 
         * @config path
2230
 
         * @type String
2231
 
     * @readOnly
2232
 
         */
2233
 
        path: {
2234
 
                readOnly: true,
2235
 
 
2236
 
                getter: function()
2237
 
                {
2238
 
                        return this._path;
2239
 
                }
2240
 
        },
2241
 
 
2242
 
        /**
2243
 
         * Indicates the width of the shape
2244
 
         *
2245
 
         * @config width
2246
 
         * @type Number
2247
 
         */
2248
 
        width: {
2249
 
                getter: function()
2250
 
                {
2251
 
                        var val = Math.max(this._right - this._left, 0);
2252
 
                        return val;
2253
 
                }
2254
 
        },
2255
 
 
2256
 
        /**
2257
 
         * Indicates the height of the shape
2258
 
         *
2259
 
         * @config height
2260
 
         * @type Number
2261
 
         */
2262
 
        height: {
2263
 
                getter: function()
2264
 
                {
2265
 
                        return Math.max(this._bottom - this._top, 0);
2266
 
                }
2267
 
        }
2268
 
});
2269
 
Y.SVGPath = SVGPath;
2270
 
/**
2271
 
 * <a href="http://www.w3.org/TR/SVG/">SVG</a> implementation of the <a href="Rect.html">`Rect`</a> class.
2272
 
 * `SVGRect` is not intended to be used directly. Instead, use the <a href="Rect.html">`Rect`</a> class.
2273
 
 * If the browser has <a href="http://www.w3.org/TR/SVG/">SVG</a> capabilities, the <a href="Rect.html">`Rect`</a>
2274
 
 * class will point to the `SVGRect` class.
2275
 
 *
2276
 
 * @module graphics
2277
 
 * @class SVGRect
2278
 
 * @constructor
2279
 
 */
2280
 
SVGRect = function()
2281
 
{
2282
 
        SVGRect.superclass.constructor.apply(this, arguments);
2283
 
};
2284
 
SVGRect.NAME = "rect";
2285
 
Y.extend(SVGRect, Y.SVGShape, {
2286
 
    /**
2287
 
     * Indicates the type of shape
2288
 
     *
2289
 
     * @property _type
2290
 
     * @type String
2291
 
     * @private
2292
 
     */
2293
 
    _type: "rect"
2294
 
 });
2295
 
SVGRect.ATTRS = Y.SVGShape.ATTRS;
2296
 
Y.SVGRect = SVGRect;
2297
 
/**
2298
 
 * <a href="http://www.w3.org/TR/SVG/">SVG</a> implementation of the <a href="Ellipse.html">`Ellipse`</a> class.
2299
 
 * `SVGEllipse` is not intended to be used directly. Instead, use the <a href="Ellipse.html">`Ellipse`</a> class.
2300
 
 * If the browser has <a href="http://www.w3.org/TR/SVG/">SVG</a> capabilities, the <a href="Ellipse.html">`Ellipse`</a>
2301
 
 * class will point to the `SVGEllipse` class.
2302
 
 *
2303
 
 * @module graphics
2304
 
 * @class SVGEllipse
2305
 
 * @constructor
2306
 
 */
2307
 
SVGEllipse = function()
2308
 
{
2309
 
        SVGEllipse.superclass.constructor.apply(this, arguments);
2310
 
};
2311
 
 
2312
 
SVGEllipse.NAME = "ellipse";
2313
 
 
2314
 
Y.extend(SVGEllipse, SVGShape, {
2315
 
        /**
2316
 
         * Indicates the type of shape
2317
 
         *
2318
 
         * @property _type
2319
 
         * @type String
2320
 
     * @private
2321
 
         */
2322
 
        _type: "ellipse",
2323
 
 
2324
 
        /**
2325
 
         * Updates the shape.
2326
 
         *
2327
 
         * @method _draw
2328
 
         * @private
2329
 
         */
2330
 
        _draw: function()
2331
 
        {
2332
 
                var node = this.node,
2333
 
                        w = this.get("width"),
2334
 
                        h = this.get("height"),
2335
 
                        x = this.get("x"),
2336
 
                        y = this.get("y"),
2337
 
                        xRadius = w * 0.5,
2338
 
                        yRadius = h * 0.5,
2339
 
                        cx = x + xRadius,
2340
 
                        cy = y + yRadius;
2341
 
                node.setAttribute("rx", xRadius);
2342
 
                node.setAttribute("ry", yRadius);
2343
 
                node.setAttribute("cx", cx);
2344
 
                node.setAttribute("cy", cy);
2345
 
                this._fillChangeHandler();
2346
 
                this._strokeChangeHandler();
2347
 
                this._updateTransform();
2348
 
        }
2349
 
});
2350
 
 
2351
 
SVGEllipse.ATTRS = Y.merge(SVGShape.ATTRS, {
2352
 
        /**
2353
 
         * Horizontal radius for the ellipse.
2354
 
         *
2355
 
         * @config xRadius
2356
 
         * @type Number
2357
 
         */
2358
 
        xRadius: {
2359
 
                setter: function(val)
2360
 
                {
2361
 
                        this.set("width", val * 2);
2362
 
                },
2363
 
 
2364
 
                getter: function()
2365
 
                {
2366
 
                        var val = this.get("width");
2367
 
                        if(val)
2368
 
                        {
2369
 
                                val *= 0.5;
2370
 
                        }
2371
 
                        return val;
2372
 
                }
2373
 
        },
2374
 
 
2375
 
        /**
2376
 
         * Vertical radius for the ellipse.
2377
 
         *
2378
 
         * @config yRadius
2379
 
         * @type Number
2380
 
         * @readOnly
2381
 
         */
2382
 
        yRadius: {
2383
 
                setter: function(val)
2384
 
                {
2385
 
                        this.set("height", val * 2);
2386
 
                },
2387
 
 
2388
 
                getter: function()
2389
 
                {
2390
 
                        var val = this.get("height");
2391
 
                        if(val)
2392
 
                        {
2393
 
                                val *= 0.5;
2394
 
                        }
2395
 
                        return val;
2396
 
                }
2397
 
        }
2398
 
});
2399
 
Y.SVGEllipse = SVGEllipse;
2400
 
/**
2401
 
 * <a href="http://www.w3.org/TR/SVG/">SVG</a> implementation of the <a href="Circle.html">`Circle`</a> class.
2402
 
 * `SVGCircle` is not intended to be used directly. Instead, use the <a href="Circle.html">`Circle`</a> class.
2403
 
 * If the browser has <a href="http://www.w3.org/TR/SVG/">SVG</a> capabilities, the <a href="Circle.html">`Circle`</a>
2404
 
 * class will point to the `SVGCircle` class.
2405
 
 *
2406
 
 * @module graphics
2407
 
 * @class SVGCircle
2408
 
 * @constructor
2409
 
 */
2410
 
 SVGCircle = function()
2411
 
 {
2412
 
    SVGCircle.superclass.constructor.apply(this, arguments);
2413
 
 };
2414
 
 
2415
 
 SVGCircle.NAME = "circle";
2416
 
 
2417
 
 Y.extend(SVGCircle, Y.SVGShape, {
2418
 
 
2419
 
    /**
2420
 
     * Indicates the type of shape
2421
 
     *
2422
 
     * @property _type
2423
 
     * @type String
2424
 
     * @private
2425
 
     */
2426
 
    _type: "circle",
2427
 
 
2428
 
    /**
2429
 
     * Updates the shape.
2430
 
     *
2431
 
     * @method _draw
2432
 
     * @private
2433
 
     */
2434
 
    _draw: function()
2435
 
    {
2436
 
        var node = this.node,
2437
 
            x = this.get("x"),
2438
 
            y = this.get("y"),
2439
 
            radius = this.get("radius"),
2440
 
            cx = x + radius,
2441
 
            cy = y + radius;
2442
 
        node.setAttribute("r", radius);
2443
 
        node.setAttribute("cx", cx);
2444
 
        node.setAttribute("cy", cy);
2445
 
        this._fillChangeHandler();
2446
 
        this._strokeChangeHandler();
2447
 
        this._updateTransform();
2448
 
    }
2449
 
 });
2450
 
 
2451
 
SVGCircle.ATTRS = Y.merge(Y.SVGShape.ATTRS, {
2452
 
        /**
2453
 
         * Indicates the width of the shape
2454
 
         *
2455
 
         * @config width
2456
 
         * @type Number
2457
 
         */
2458
 
    width: {
2459
 
        setter: function(val)
2460
 
        {
2461
 
            this.set("radius", val/2);
2462
 
            return val;
2463
 
        },
2464
 
 
2465
 
        getter: function()
2466
 
        {
2467
 
            return this.get("radius") * 2;
2468
 
        }
2469
 
    },
2470
 
 
2471
 
        /**
2472
 
         * Indicates the height of the shape
2473
 
         *
2474
 
         * @config height
2475
 
         * @type Number
2476
 
         */
2477
 
    height: {
2478
 
        setter: function(val)
2479
 
        {
2480
 
            this.set("radius", val/2);
2481
 
            return val;
2482
 
        },
2483
 
 
2484
 
        getter: function()
2485
 
        {
2486
 
            return this.get("radius") * 2;
2487
 
        }
2488
 
    },
2489
 
 
2490
 
    /**
2491
 
     * Radius of the circle
2492
 
     *
2493
 
     * @config radius
2494
 
     * @type Number
2495
 
     */
2496
 
    radius: {
2497
 
        value: 0
2498
 
    }
2499
 
});
2500
 
Y.SVGCircle = SVGCircle;
2501
 
/**
2502
 
 * Draws pie slices
2503
 
 *
2504
 
 * @module graphics
2505
 
 * @class SVGPieSlice
2506
 
 * @constructor
2507
 
 */
2508
 
SVGPieSlice = function()
2509
 
{
2510
 
        SVGPieSlice.superclass.constructor.apply(this, arguments);
2511
 
};
2512
 
SVGPieSlice.NAME = "svgPieSlice";
2513
 
Y.extend(SVGPieSlice, Y.SVGShape, Y.mix({
2514
 
    /**
2515
 
     * Indicates the type of shape
2516
 
     *
2517
 
     * @property _type
2518
 
     * @type String
2519
 
     * @private
2520
 
     */
2521
 
    _type: "path",
2522
 
 
2523
 
        /**
2524
 
         * Change event listener
2525
 
         *
2526
 
         * @private
2527
 
         * @method _updateHandler
2528
 
         */
2529
 
        _draw: function()
2530
 
        {
2531
 
        var x = this.get("cx"),
2532
 
            y = this.get("cy"),
2533
 
            startAngle = this.get("startAngle"),
2534
 
            arc = this.get("arc"),
2535
 
            radius = this.get("radius");
2536
 
        this.clear();
2537
 
        this.drawWedge(x, y, startAngle, arc, radius);
2538
 
                this.end();
2539
 
        }
2540
 
 }, Y.SVGDrawing.prototype));
2541
 
SVGPieSlice.ATTRS = Y.mix({
2542
 
    cx: {
2543
 
        value: 0
2544
 
    },
2545
 
 
2546
 
    cy: {
2547
 
        value: 0
2548
 
    },
2549
 
    /**
2550
 
     * Starting angle in relation to a circle in which to begin the pie slice drawing.
2551
 
     *
2552
 
     * @config startAngle
2553
 
     * @type Number
2554
 
     */
2555
 
    startAngle: {
2556
 
        value: 0
2557
 
    },
2558
 
 
2559
 
    /**
2560
 
     * Arc of the slice.
2561
 
     *
2562
 
     * @config arc
2563
 
     * @type Number
2564
 
     */
2565
 
    arc: {
2566
 
        value: 0
2567
 
    },
2568
 
 
2569
 
    /**
2570
 
     * Radius of the circle in which the pie slice is drawn
2571
 
     *
2572
 
     * @config radius
2573
 
     * @type Number
2574
 
     */
2575
 
    radius: {
2576
 
        value: 0
2577
 
    }
2578
 
}, Y.SVGShape.ATTRS);
2579
 
Y.SVGPieSlice = SVGPieSlice;
2580
 
/**
2581
 
 * <a href="http://www.w3.org/TR/SVG/">SVG</a> implementation of the <a href="Graphic.html">`Graphic`</a> class.
2582
 
 * `SVGGraphic` is not intended to be used directly. Instead, use the <a href="Graphic.html">`Graphic`</a> class.
2583
 
 * If the browser has <a href="http://www.w3.org/TR/SVG/">SVG</a> capabilities, the <a href="Graphic.html">`Graphic`</a>
2584
 
 * class will point to the `SVGGraphic` class.
2585
 
 *
2586
 
 * @module graphics
2587
 
 * @class SVGGraphic
2588
 
 * @constructor
2589
 
 */
2590
 
SVGGraphic = function() {
2591
 
    SVGGraphic.superclass.constructor.apply(this, arguments);
2592
 
};
2593
 
 
2594
 
SVGGraphic.NAME = "svgGraphic";
2595
 
 
2596
 
SVGGraphic.ATTRS = {
2597
 
    /**
2598
 
     * Whether or not to render the `Graphic` automatically after to a specified parent node after init. This can be a Node
2599
 
     * instance or a CSS selector string.
2600
 
     *
2601
 
     * @config render
2602
 
     * @type Node | String
2603
 
     */
2604
 
    render: {},
2605
 
 
2606
 
    /**
2607
 
         * Unique id for class instance.
2608
 
         *
2609
 
         * @config id
2610
 
         * @type String
2611
 
         */
2612
 
        id: {
2613
 
                valueFn: function()
2614
 
                {
2615
 
                        return Y.guid();
2616
 
                },
2617
 
 
2618
 
                setter: function(val)
2619
 
                {
2620
 
                        var node = this._node;
2621
 
                        if(node)
2622
 
                        {
2623
 
                                node.setAttribute("id", val);
2624
 
                        }
2625
 
                        return val;
2626
 
                }
2627
 
        },
2628
 
 
2629
 
    /**
2630
 
     * Key value pairs in which a shape instance is associated with its id.
2631
 
     *
2632
 
     *  @config shapes
2633
 
     *  @type Object
2634
 
     *  @readOnly
2635
 
     */
2636
 
    shapes: {
2637
 
        readOnly: true,
2638
 
 
2639
 
        getter: function()
2640
 
        {
2641
 
            return this._shapes;
2642
 
        }
2643
 
    },
2644
 
 
2645
 
    /**
2646
 
     *  Object containing size and coordinate data for the content of a Graphic in relation to the coordSpace node.
2647
 
     *
2648
 
     *  @config contentBounds
2649
 
     *  @type Object
2650
 
     *  @readOnly
2651
 
     */
2652
 
    contentBounds: {
2653
 
        readOnly: true,
2654
 
 
2655
 
        getter: function()
2656
 
        {
2657
 
            return this._contentBounds;
2658
 
        }
2659
 
    },
2660
 
 
2661
 
    /**
2662
 
     *  The html element that represents to coordinate system of the Graphic instance.
2663
 
     *
2664
 
     *  @config node
2665
 
     *  @type HTMLElement
2666
 
     *  @readOnly
2667
 
     */
2668
 
    node: {
2669
 
        readOnly: true,
2670
 
 
2671
 
        getter: function()
2672
 
        {
2673
 
            return this._node;
2674
 
        }
2675
 
    },
2676
 
 
2677
 
        /**
2678
 
         * Indicates the width of the `Graphic`.
2679
 
         *
2680
 
         * @config width
2681
 
         * @type Number
2682
 
         */
2683
 
    width: {
2684
 
        setter: function(val)
2685
 
        {
2686
 
            if(this._node)
2687
 
            {
2688
 
                this._node.style.width = val + "px";
2689
 
            }
2690
 
            return val;
2691
 
        }
2692
 
    },
2693
 
 
2694
 
        /**
2695
 
         * Indicates the height of the `Graphic`.
2696
 
         *
2697
 
         * @config height
2698
 
         * @type Number
2699
 
         */
2700
 
    height: {
2701
 
        setter: function(val)
2702
 
        {
2703
 
            if(this._node)
2704
 
            {
2705
 
                this._node.style.height = val  + "px";
2706
 
            }
2707
 
            return val;
2708
 
        }
2709
 
    },
2710
 
 
2711
 
    /**
2712
 
     *  Determines the sizing of the Graphic.
2713
 
     *
2714
 
     *  <dl>
2715
 
     *      <dt>sizeContentToGraphic</dt><dd>The Graphic's width and height attributes are, either explicitly set through the
2716
 
     *      <code>width</code> and <code>height</code> attributes or are determined by the dimensions of the parent element. The
2717
 
     *      content contained in the Graphic will be sized to fit with in the Graphic instance's dimensions. When using this
2718
 
     *      setting, the <code>preserveAspectRatio</code> attribute will determine how the contents are sized.</dd>
2719
 
     *      <dt>sizeGraphicToContent</dt><dd>(Also accepts a value of true) The Graphic's width and height are determined by the
2720
 
     *      size and positioning of the content.</dd>
2721
 
     *      <dt>false</dt><dd>The Graphic's width and height attributes are, either explicitly set through the <code>width</code>
2722
 
     *      and <code>height</code> attributes or are determined by the dimensions of the parent element. The contents of the
2723
 
     *      Graphic instance are not affected by this setting.</dd>
2724
 
     *  </dl>
2725
 
     *
2726
 
     *
2727
 
     *  @config autoSize
2728
 
     *  @type Boolean | String
2729
 
     *  @default false
2730
 
     */
2731
 
    autoSize: {
2732
 
        value: false
2733
 
    },
2734
 
 
2735
 
    /**
2736
 
     * Determines how content is sized when <code>autoSize</code> is set to <code>sizeContentToGraphic</code>.
2737
 
     *
2738
 
     *  <dl>
2739
 
     *      <dt>none<dt><dd>Do not force uniform scaling. Scale the graphic content of the given element non-uniformly if necessary
2740
 
     *      such that the element's bounding box exactly matches the viewport rectangle.</dd>
2741
 
     *      <dt>xMinYMin</dt><dd>Force uniform scaling position along the top left of the Graphic's node.</dd>
2742
 
     *      <dt>xMidYMin</dt><dd>Force uniform scaling horizontally centered and positioned at the top of the Graphic's node.<dd>
2743
 
     *      <dt>xMaxYMin</dt><dd>Force uniform scaling positioned horizontally from the right and vertically from the top.</dd>
2744
 
     *      <dt>xMinYMid</dt>Force uniform scaling positioned horizontally from the left and vertically centered.</dd>
2745
 
     *      <dt>xMidYMid (the default)</dt><dd>Force uniform scaling with the content centered.</dd>
2746
 
     *      <dt>xMaxYMid</dt><dd>Force uniform scaling positioned horizontally from the right and vertically centered.</dd>
2747
 
     *      <dt>xMinYMax</dt><dd>Force uniform scaling positioned horizontally from the left and vertically from the bottom.</dd>
2748
 
     *      <dt>xMidYMax</dt><dd>Force uniform scaling horizontally centered and position vertically from the bottom.</dd>
2749
 
     *      <dt>xMaxYMax</dt><dd>Force uniform scaling positioned horizontally from the right and vertically from the bottom.</dd>
2750
 
     *  </dl>
2751
 
     *
2752
 
     * @config preserveAspectRatio
2753
 
     * @type String
2754
 
     * @default xMidYMid
2755
 
     */
2756
 
    preserveAspectRatio: {
2757
 
        value: "xMidYMid"
2758
 
    },
2759
 
 
2760
 
    /**
2761
 
     * The contentBounds will resize to greater values but not to smaller values. (for performance)
2762
 
     * When resizing the contentBounds down is desirable, set the resizeDown value to true.
2763
 
     *
2764
 
     * @config resizeDown
2765
 
     * @type Boolean
2766
 
     */
2767
 
    resizeDown: {
2768
 
        value: false
2769
 
    },
2770
 
 
2771
 
        /**
2772
 
         * Indicates the x-coordinate for the instance.
2773
 
         *
2774
 
         * @config x
2775
 
         * @type Number
2776
 
         */
2777
 
    x: {
2778
 
        getter: function()
2779
 
        {
2780
 
            return this._x;
2781
 
        },
2782
 
 
2783
 
        setter: function(val)
2784
 
        {
2785
 
            this._x = val;
2786
 
            if(this._node)
2787
 
            {
2788
 
                this._node.style.left = val + "px";
2789
 
            }
2790
 
            return val;
2791
 
        }
2792
 
    },
2793
 
 
2794
 
        /**
2795
 
         * Indicates the y-coordinate for the instance.
2796
 
         *
2797
 
         * @config y
2798
 
         * @type Number
2799
 
         */
2800
 
    y: {
2801
 
        getter: function()
2802
 
        {
2803
 
            return this._y;
2804
 
        },
2805
 
 
2806
 
        setter: function(val)
2807
 
        {
2808
 
            this._y = val;
2809
 
            if(this._node)
2810
 
            {
2811
 
                this._node.style.top = val + "px";
2812
 
            }
2813
 
            return val;
2814
 
        }
2815
 
    },
2816
 
 
2817
 
    /**
2818
 
     * Indicates whether or not the instance will automatically redraw after a change is made to a shape.
2819
 
     * This property will get set to false when batching operations.
2820
 
     *
2821
 
     * @config autoDraw
2822
 
     * @type Boolean
2823
 
     * @default true
2824
 
     * @private
2825
 
     */
2826
 
    autoDraw: {
2827
 
        value: true
2828
 
    },
2829
 
 
2830
 
    visible: {
2831
 
        value: true,
2832
 
 
2833
 
        setter: function(val)
2834
 
        {
2835
 
            this._toggleVisible(val);
2836
 
            return val;
2837
 
        }
2838
 
    },
2839
 
 
2840
 
    //
2841
 
    //  Indicates the pointer-events setting for the svg:svg element.
2842
 
    //
2843
 
    //  @config pointerEvents
2844
 
    //  @type String
2845
 
    //
2846
 
    pointerEvents: {
2847
 
        value: "none"
2848
 
    }
2849
 
};
2850
 
 
2851
 
Y.extend(SVGGraphic, Y.GraphicBase, {
2852
 
    /**
2853
 
     * Sets the value of an attribute.
2854
 
     *
2855
 
     * @method set
2856
 
     * @param {String|Object} name The name of the attribute. Alternatively, an object of key value pairs can
2857
 
     * be passed in to set multiple attributes at once.
2858
 
     * @param {Any} value The value to set the attribute to. This value is ignored if an object is received as
2859
 
     * the name param.
2860
 
     */
2861
 
        set: function()
2862
 
        {
2863
 
                var host = this,
2864
 
            attr = arguments[0],
2865
 
            redrawAttrs = {
2866
 
                autoDraw: true,
2867
 
                autoSize: true,
2868
 
                preserveAspectRatio: true,
2869
 
                resizeDown: true
2870
 
            },
2871
 
            key,
2872
 
            forceRedraw = false;
2873
 
                AttributeLite.prototype.set.apply(host, arguments);
2874
 
        if(host._state.autoDraw === true && Y.Object.size(this._shapes) > 0)
2875
 
        {
2876
 
            if(Y_LANG.isString && redrawAttrs[attr])
2877
 
            {
2878
 
                forceRedraw = true;
2879
 
            }
2880
 
            else if(Y_LANG.isObject(attr))
2881
 
            {
2882
 
                for(key in redrawAttrs)
2883
 
                {
2884
 
                    if(redrawAttrs.hasOwnProperty(key) && attr[key])
2885
 
                    {
2886
 
                        forceRedraw = true;
2887
 
                        break;
2888
 
                    }
2889
 
                }
2890
 
            }
2891
 
        }
2892
 
        if(forceRedraw)
2893
 
        {
2894
 
            host._redraw();
2895
 
        }
2896
 
        },
2897
 
 
2898
 
    /**
2899
 
     * Storage for `x` attribute.
2900
 
     *
2901
 
     * @property _x
2902
 
     * @type Number
2903
 
     * @private
2904
 
     */
2905
 
    _x: 0,
2906
 
 
2907
 
    /**
2908
 
     * Storage for `y` attribute.
2909
 
     *
2910
 
     * @property _y
2911
 
     * @type Number
2912
 
     * @private
2913
 
     */
2914
 
    _y: 0,
2915
 
 
2916
 
    /**
2917
 
     * Gets the current position of the graphic instance in page coordinates.
2918
 
     *
2919
 
     * @method getXY
2920
 
     * @return Array The XY position of the shape.
2921
 
     */
2922
 
    getXY: function()
2923
 
    {
2924
 
        var node = Y.one(this._node),
2925
 
            xy;
2926
 
        if(node)
2927
 
        {
2928
 
            xy = node.getXY();
2929
 
        }
2930
 
        return xy;
2931
 
    },
2932
 
 
2933
 
    /**
2934
 
     * Initializes the class.
2935
 
     *
2936
 
     * @method initializer
2937
 
     * @private
2938
 
     */
2939
 
    initializer: function() {
2940
 
        var render = this.get("render"),
2941
 
            visibility = this.get("visible") ? "visible" : "hidden";
2942
 
        this._shapes = {};
2943
 
                this._contentBounds = {
2944
 
            left: 0,
2945
 
            top: 0,
2946
 
            right: 0,
2947
 
            bottom: 0
2948
 
        };
2949
 
        this._gradients = {};
2950
 
        this._node = DOCUMENT.createElement('div');
2951
 
        this._node.style.position = "absolute";
2952
 
        this._node.style.left = this.get("x") + "px";
2953
 
        this._node.style.top = this.get("y") + "px";
2954
 
        this._node.style.visibility = visibility;
2955
 
        this._contentNode = this._createGraphics();
2956
 
        this._contentNode.style.visibility = visibility;
2957
 
        this._contentNode.setAttribute("id", this.get("id"));
2958
 
        this._node.appendChild(this._contentNode);
2959
 
        if(render)
2960
 
        {
2961
 
            this.render(render);
2962
 
        }
2963
 
    },
2964
 
 
2965
 
    /**
2966
 
     * Adds the graphics node to the dom.
2967
 
     *
2968
 
     * @method render
2969
 
     * @param {HTMLElement} parentNode node in which to render the graphics node into.
2970
 
     */
2971
 
    render: function(render) {
2972
 
        var parentNode = Y.one(render),
2973
 
            w = this.get("width") || parseInt(parentNode.getComputedStyle("width"), 10),
2974
 
            h = this.get("height") || parseInt(parentNode.getComputedStyle("height"), 10);
2975
 
        parentNode = parentNode || Y.one(DOCUMENT.body);
2976
 
        parentNode.append(this._node);
2977
 
        this.parentNode = parentNode;
2978
 
        this.set("width", w);
2979
 
        this.set("height", h);
2980
 
        return this;
2981
 
    },
2982
 
 
2983
 
    /**
2984
 
     * Removes all nodes.
2985
 
     *
2986
 
     * @method destroy
2987
 
     */
2988
 
    destroy: function()
2989
 
    {
2990
 
        this.removeAllShapes();
2991
 
        if(this._contentNode)
2992
 
        {
2993
 
            this._removeChildren(this._contentNode);
2994
 
            if(this._contentNode.parentNode)
2995
 
            {
2996
 
                this._contentNode.parentNode.removeChild(this._contentNode);
2997
 
            }
2998
 
            this._contentNode = null;
2999
 
        }
3000
 
        if(this._node)
3001
 
        {
3002
 
            this._removeChildren(this._node);
3003
 
            Y.one(this._node).remove(true);
3004
 
            this._node = null;
3005
 
        }
3006
 
    },
3007
 
 
3008
 
    /**
3009
 
     * Generates a shape instance by type.
3010
 
     *
3011
 
     * @method addShape
3012
 
     * @param {Object} cfg attributes for the shape
3013
 
     * @return Shape
3014
 
     */
3015
 
    addShape: function(cfg)
3016
 
    {
3017
 
        cfg.graphic = this;
3018
 
        if(!this.get("visible"))
3019
 
        {
3020
 
            cfg.visible = false;
3021
 
        }
3022
 
        var ShapeClass = this._getShapeClass(cfg.type),
3023
 
            shape = new ShapeClass(cfg);
3024
 
        this._appendShape(shape);
3025
 
        return shape;
3026
 
    },
3027
 
 
3028
 
    /**
3029
 
     * Adds a shape instance to the graphic instance.
3030
 
     *
3031
 
     * @method _appendShape
3032
 
     * @param {Shape} shape The shape instance to be added to the graphic.
3033
 
     * @private
3034
 
     */
3035
 
    _appendShape: function(shape)
3036
 
    {
3037
 
        var node = shape.node,
3038
 
            parentNode = this._frag || this._contentNode;
3039
 
        if(this.get("autoDraw"))
3040
 
        {
3041
 
            parentNode.appendChild(node);
3042
 
        }
3043
 
        else
3044
 
        {
3045
 
            this._getDocFrag().appendChild(node);
3046
 
        }
3047
 
    },
3048
 
 
3049
 
    /**
3050
 
     * Removes a shape instance from from the graphic instance.
3051
 
     *
3052
 
     * @method removeShape
3053
 
     * @param {Shape|String} shape The instance or id of the shape to be removed.
3054
 
     */
3055
 
    removeShape: function(shape)
3056
 
    {
3057
 
        if(!(shape instanceof SVGShape))
3058
 
        {
3059
 
            if(Y_LANG.isString(shape))
3060
 
            {
3061
 
                shape = this._shapes[shape];
3062
 
            }
3063
 
        }
3064
 
        if(shape && shape instanceof SVGShape)
3065
 
        {
3066
 
            shape._destroy();
3067
 
            delete this._shapes[shape.get("id")];
3068
 
        }
3069
 
        if(this.get("autoDraw"))
3070
 
        {
3071
 
            this._redraw();
3072
 
        }
3073
 
        return shape;
3074
 
    },
3075
 
 
3076
 
    /**
3077
 
     * Removes all shape instances from the dom.
3078
 
     *
3079
 
     * @method removeAllShapes
3080
 
     */
3081
 
    removeAllShapes: function()
3082
 
    {
3083
 
        var shapes = this._shapes,
3084
 
            i;
3085
 
        for(i in shapes)
3086
 
        {
3087
 
            if(shapes.hasOwnProperty(i))
3088
 
            {
3089
 
                shapes[i]._destroy();
3090
 
            }
3091
 
        }
3092
 
        this._shapes = {};
3093
 
    },
3094
 
 
3095
 
    /**
3096
 
     * Removes all child nodes.
3097
 
     *
3098
 
     * @method _removeChildren
3099
 
     * @param {HTMLElement} node
3100
 
     * @private
3101
 
     */
3102
 
    _removeChildren: function(node)
3103
 
    {
3104
 
        if(node.hasChildNodes())
3105
 
        {
3106
 
            var child;
3107
 
            while(node.firstChild)
3108
 
            {
3109
 
                child = node.firstChild;
3110
 
                this._removeChildren(child);
3111
 
                node.removeChild(child);
3112
 
            }
3113
 
        }
3114
 
    },
3115
 
 
3116
 
    /**
3117
 
     * Clears the graphics object.
3118
 
     *
3119
 
     * @method clear
3120
 
     */
3121
 
    clear: function() {
3122
 
        this.removeAllShapes();
3123
 
    },
3124
 
 
3125
 
    /**
3126
 
     * Toggles visibility
3127
 
     *
3128
 
     * @method _toggleVisible
3129
 
     * @param {Boolean} val indicates visibilitye
3130
 
     * @private
3131
 
     */
3132
 
    _toggleVisible: function(val)
3133
 
    {
3134
 
        var i,
3135
 
            shapes = this._shapes,
3136
 
            visibility = val ? "visible" : "hidden";
3137
 
        if(shapes)
3138
 
        {
3139
 
            for(i in shapes)
3140
 
            {
3141
 
                if(shapes.hasOwnProperty(i))
3142
 
                {
3143
 
                    shapes[i].set("visible", val);
3144
 
                }
3145
 
            }
3146
 
        }
3147
 
        if(this._contentNode)
3148
 
        {
3149
 
            this._contentNode.style.visibility = visibility;
3150
 
        }
3151
 
        if(this._node)
3152
 
        {
3153
 
            this._node.style.visibility = visibility;
3154
 
        }
3155
 
    },
3156
 
 
3157
 
    /**
3158
 
     * Returns a shape class. Used by `addShape`.
3159
 
     *
3160
 
     * @method _getShapeClass
3161
 
     * @param {Shape | String} val Indicates which shape class.
3162
 
     * @return Function
3163
 
     * @private
3164
 
     */
3165
 
    _getShapeClass: function(val)
3166
 
    {
3167
 
        var shape = this._shapeClass[val];
3168
 
        if(shape)
3169
 
        {
3170
 
            return shape;
3171
 
        }
3172
 
        return val;
3173
 
    },
3174
 
 
3175
 
    /**
3176
 
     * Look up for shape classes. Used by `addShape` to retrieve a class for instantiation.
3177
 
     *
3178
 
     * @property _shapeClass
3179
 
     * @type Object
3180
 
     * @private
3181
 
     */
3182
 
    _shapeClass: {
3183
 
        circle: Y.SVGCircle,
3184
 
        rect: Y.SVGRect,
3185
 
        path: Y.SVGPath,
3186
 
        ellipse: Y.SVGEllipse,
3187
 
        pieslice: Y.SVGPieSlice
3188
 
    },
3189
 
 
3190
 
    /**
3191
 
     * Returns a shape based on the id of its dom node.
3192
 
     *
3193
 
     * @method getShapeById
3194
 
     * @param {String} id Dom id of the shape's node attribute.
3195
 
     * @return Shape
3196
 
     */
3197
 
    getShapeById: function(id)
3198
 
    {
3199
 
        var shape = this._shapes[id];
3200
 
        return shape;
3201
 
    },
3202
 
 
3203
 
        /**
3204
 
         * Allows for creating multiple shapes in order to batch appending and redraw operations.
3205
 
         *
3206
 
         * @method batch
3207
 
         * @param {Function} method Method to execute.
3208
 
         */
3209
 
    batch: function(method)
3210
 
    {
3211
 
        var autoDraw = this.get("autoDraw");
3212
 
        this.set("autoDraw", false);
3213
 
        method();
3214
 
        this.set("autoDraw", autoDraw);
3215
 
    },
3216
 
 
3217
 
    /**
3218
 
     * Returns a document fragment to for attaching shapes.
3219
 
     *
3220
 
     * @method _getDocFrag
3221
 
     * @return DocumentFragment
3222
 
     * @private
3223
 
     */
3224
 
    _getDocFrag: function()
3225
 
    {
3226
 
        if(!this._frag)
3227
 
        {
3228
 
            this._frag = DOCUMENT.createDocumentFragment();
3229
 
        }
3230
 
        return this._frag;
3231
 
    },
3232
 
 
3233
 
    /**
3234
 
     * Redraws all shapes.
3235
 
     *
3236
 
     * @method _redraw
3237
 
     * @private
3238
 
     */
3239
 
    _redraw: function()
3240
 
    {
3241
 
        var autoSize = this.get("autoSize"),
3242
 
            preserveAspectRatio = this.get("preserveAspectRatio"),
3243
 
            box = this.get("resizeDown") ? this._getUpdatedContentBounds() : this._contentBounds,
3244
 
            left = box.left,
3245
 
            right = box.right,
3246
 
            top = box.top,
3247
 
            bottom = box.bottom,
3248
 
            width = right - left,
3249
 
            height = bottom - top,
3250
 
            computedWidth,
3251
 
            computedHeight,
3252
 
            computedLeft,
3253
 
            computedTop,
3254
 
            node;
3255
 
        if(autoSize)
3256
 
        {
3257
 
            if(autoSize === "sizeContentToGraphic")
3258
 
            {
3259
 
                node = Y.one(this._node);
3260
 
                computedWidth = parseFloat(node.getComputedStyle("width"));
3261
 
                computedHeight = parseFloat(node.getComputedStyle("height"));
3262
 
                computedLeft = computedTop = 0;
3263
 
                this._contentNode.setAttribute("preserveAspectRatio", preserveAspectRatio);
3264
 
            }
3265
 
            else
3266
 
            {
3267
 
                computedWidth = width;
3268
 
                computedHeight = height;
3269
 
                computedLeft = left;
3270
 
                computedTop = top;
3271
 
                this._state.width = width;
3272
 
                this._state.height = height;
3273
 
                if(this._node)
3274
 
                {
3275
 
                    this._node.style.width = width + "px";
3276
 
                    this._node.style.height = height + "px";
3277
 
                }
3278
 
            }
3279
 
        }
3280
 
        else
3281
 
        {
3282
 
                computedWidth = width;
3283
 
                computedHeight = height;
3284
 
                computedLeft = left;
3285
 
                computedTop = top;
3286
 
        }
3287
 
        if(this._contentNode)
3288
 
        {
3289
 
            this._contentNode.style.left = computedLeft + "px";
3290
 
            this._contentNode.style.top = computedTop + "px";
3291
 
            this._contentNode.setAttribute("width", computedWidth);
3292
 
            this._contentNode.setAttribute("height", computedHeight);
3293
 
            this._contentNode.style.width = computedWidth + "px";
3294
 
            this._contentNode.style.height = computedHeight + "px";
3295
 
            this._contentNode.setAttribute("viewBox", "" + left + " " + top + " " + width + " " + height + "");
3296
 
        }
3297
 
        if(this._frag)
3298
 
        {
3299
 
            if(this._contentNode)
3300
 
            {
3301
 
                this._contentNode.appendChild(this._frag);
3302
 
            }
3303
 
            this._frag = null;
3304
 
        }
3305
 
    },
3306
 
 
3307
 
    /**
3308
 
     * Adds a shape to the redraw queue and calculates the contentBounds. Used internally
3309
 
     * by `Shape` instances.
3310
 
     *
3311
 
     * @method addToRedrawQueue
3312
 
     * @param shape {SVGShape}
3313
 
     * @protected
3314
 
     */
3315
 
    addToRedrawQueue: function(shape)
3316
 
    {
3317
 
        var shapeBox,
3318
 
            box;
3319
 
        this._shapes[shape.get("id")] = shape;
3320
 
        if(!this.get("resizeDown"))
3321
 
        {
3322
 
            shapeBox = shape.getBounds();
3323
 
            box = this._contentBounds;
3324
 
            box.left = box.left < shapeBox.left ? box.left : shapeBox.left;
3325
 
            box.top = box.top < shapeBox.top ? box.top : shapeBox.top;
3326
 
            box.right = box.right > shapeBox.right ? box.right : shapeBox.right;
3327
 
            box.bottom = box.bottom > shapeBox.bottom ? box.bottom : shapeBox.bottom;
3328
 
            box.width = box.right - box.left;
3329
 
            box.height = box.bottom - box.top;
3330
 
            this._contentBounds = box;
3331
 
        }
3332
 
        if(this.get("autoDraw"))
3333
 
        {
3334
 
            this._redraw();
3335
 
        }
3336
 
    },
3337
 
 
3338
 
    /**
3339
 
     * Recalculates and returns the `contentBounds` for the `Graphic` instance.
3340
 
     *
3341
 
     * @method _getUpdatedContentBounds
3342
 
     * @return {Object}
3343
 
     * @private
3344
 
     */
3345
 
    _getUpdatedContentBounds: function()
3346
 
    {
3347
 
        var bounds,
3348
 
            i,
3349
 
            shape,
3350
 
            queue = this._shapes,
3351
 
            box = {};
3352
 
        for(i in queue)
3353
 
        {
3354
 
            if(queue.hasOwnProperty(i))
3355
 
            {
3356
 
                shape = queue[i];
3357
 
                bounds = shape.getBounds();
3358
 
                box.left = Y_LANG.isNumber(box.left) ? Math.min(box.left, bounds.left) : bounds.left;
3359
 
                box.top = Y_LANG.isNumber(box.top) ? Math.min(box.top, bounds.top) : bounds.top;
3360
 
                box.right = Y_LANG.isNumber(box.right) ? Math.max(box.right, bounds.right) : bounds.right;
3361
 
                box.bottom = Y_LANG.isNumber(box.bottom) ? Math.max(box.bottom, bounds.bottom) : bounds.bottom;
3362
 
            }
3363
 
        }
3364
 
        box.left = Y_LANG.isNumber(box.left) ? box.left : 0;
3365
 
        box.top = Y_LANG.isNumber(box.top) ? box.top : 0;
3366
 
        box.right = Y_LANG.isNumber(box.right) ? box.right : 0;
3367
 
        box.bottom = Y_LANG.isNumber(box.bottom) ? box.bottom : 0;
3368
 
        this._contentBounds = box;
3369
 
        return box;
3370
 
    },
3371
 
 
3372
 
    /**
3373
 
     * Creates a contentNode element
3374
 
     *
3375
 
     * @method _createGraphics
3376
 
     * @private
3377
 
     */
3378
 
    _createGraphics: function() {
3379
 
        var contentNode = this._createGraphicNode("svg"),
3380
 
            pointerEvents = this.get("pointerEvents");
3381
 
        contentNode.style.position = "absolute";
3382
 
        contentNode.style.top = "0px";
3383
 
        contentNode.style.left = "0px";
3384
 
        contentNode.style.overflow = "auto";
3385
 
        contentNode.setAttribute("overflow", "auto");
3386
 
        contentNode.setAttribute("pointer-events", pointerEvents);
3387
 
        return contentNode;
3388
 
    },
3389
 
 
3390
 
    /**
3391
 
     * Creates a graphic node
3392
 
     *
3393
 
     * @method _createGraphicNode
3394
 
     * @param {String} type node type to create
3395
 
     * @param {String} pe specified pointer-events value
3396
 
     * @return HTMLElement
3397
 
     * @private
3398
 
     */
3399
 
    _createGraphicNode: function(type, pe)
3400
 
    {
3401
 
        var node = DOCUMENT.createElementNS("http://www.w3.org/2000/svg", "svg:" + type),
3402
 
            v = pe || "none";
3403
 
        if(type !== "defs" && type !== "stop" && type !== "linearGradient" && type !== "radialGradient")
3404
 
        {
3405
 
            node.setAttribute("pointer-events", v);
3406
 
        }
3407
 
        return node;
3408
 
    },
3409
 
 
3410
 
    /**
3411
 
     * Returns a reference to a gradient definition based on an id and type.
3412
 
     *
3413
 
     * @method getGradientNode
3414
 
     * @param {String} key id that references the gradient definition
3415
 
     * @param {String} type description of the gradient type
3416
 
     * @return HTMLElement
3417
 
     * @protected
3418
 
     */
3419
 
    getGradientNode: function(key, type)
3420
 
    {
3421
 
        var gradients = this._gradients,
3422
 
            gradient,
3423
 
            nodeType = type + "Gradient";
3424
 
        if(gradients.hasOwnProperty(key) && gradients[key].tagName.indexOf(type) > -1)
3425
 
        {
3426
 
            gradient = this._gradients[key];
3427
 
        }
3428
 
        else
3429
 
        {
3430
 
            gradient = this._createGraphicNode(nodeType);
3431
 
            if(!this._defs)
3432
 
            {
3433
 
                this._defs = this._createGraphicNode("defs");
3434
 
                this._contentNode.appendChild(this._defs);
3435
 
            }
3436
 
            this._defs.appendChild(gradient);
3437
 
            key = key || "gradient" + Math.round(100000 * Math.random());
3438
 
            gradient.setAttribute("id", key);
3439
 
            if(gradients.hasOwnProperty(key))
3440
 
            {
3441
 
                this._defs.removeChild(gradients[key]);
3442
 
            }
3443
 
            gradients[key] = gradient;
3444
 
        }
3445
 
        return gradient;
3446
 
    },
3447
 
 
3448
 
    /**
3449
 
     * Inserts shape on the top of the tree.
3450
 
     *
3451
 
     * @method _toFront
3452
 
     * @param {SVGShape} Shape to add.
3453
 
     * @private
3454
 
     */
3455
 
    _toFront: function(shape)
3456
 
    {
3457
 
        var contentNode = this._contentNode;
3458
 
        if(shape instanceof Y.SVGShape)
3459
 
        {
3460
 
            shape = shape.get("node");
3461
 
        }
3462
 
        if(contentNode && shape)
3463
 
        {
3464
 
            contentNode.appendChild(shape);
3465
 
        }
3466
 
    },
3467
 
 
3468
 
    /**
3469
 
     * Inserts shape as the first child of the content node.
3470
 
     *
3471
 
     * @method _toBack
3472
 
     * @param {SVGShape} Shape to add.
3473
 
     * @private
3474
 
     */
3475
 
    _toBack: function(shape)
3476
 
    {
3477
 
        var contentNode = this._contentNode,
3478
 
            targetNode;
3479
 
        if(shape instanceof Y.SVGShape)
3480
 
        {
3481
 
            shape = shape.get("node");
3482
 
        }
3483
 
        if(contentNode && shape)
3484
 
        {
3485
 
            targetNode = contentNode.firstChild;
3486
 
            if(targetNode)
3487
 
            {
3488
 
                contentNode.insertBefore(shape, targetNode);
3489
 
            }
3490
 
            else
3491
 
            {
3492
 
                contentNode.appendChild(shape);
3493
 
            }
3494
 
        }
3495
 
    }
3496
 
});
3497
 
 
3498
 
Y.SVGGraphic = SVGGraphic;
3499
 
 
3500
 
 
3501
 
 
3502
 
}, '3.9.1', {"requires": ["graphics"]});