~ubuntuone-pqm-team/yui/stable-min

« back to all changes in this revision

Viewing changes to build/graphics-vml/graphics-vml.js

  • Committer: Ricardo Kirkner
  • Date: 2014-09-23 20:17:06 UTC
  • Revision ID: ricardo.kirkner@canonical.com-20140923201706-17kwxwckw6orp28k
re-added all .js files

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
                        0 + "," +
 
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
}, '@VERSION@', {"requires": ["graphics"]});