Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

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