Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
YUI.add('axis', function (Y, NAME) {
2
 
3
/**
4
 * Provides base functionality for drawing chart axes.
5
 *
6
 * @module charts
7
 * @submodule axis
8
 */
9
var CONFIG = Y.config,
10
    DOCUMENT = CONFIG.doc,
11
    Y_Lang = Y.Lang,
12
    IS_STRING = Y_Lang.isString,
13
    Y_DOM = Y.DOM,
14
    LeftAxisLayout,
15
    RightAxisLayout,
16
    BottomAxisLayout,
17
    TopAxisLayout;
18
/**
19
 * Algorithmic strategy for rendering a left axis.
20
 *
21
 * @class LeftAxisLayout
22
 * @constructor
23
 * @submodule axis
24
 */
25
LeftAxisLayout = function() {};
26
 
27
LeftAxisLayout.prototype = {
28
    /**
29
     *  Default margins for text fields.
30
     *
31
     *  @private
32
     *  @method _getDefaultMargins
33
     *  @return Object
34
     */
35
    _getDefaultMargins: function()
36
    {
37
        return {
38
            top: 0,
39
            left: 0,
40
            right: 4,
41
            bottom: 0
42
        };
43
    },
44
 
45
    /**
46
     * Sets the length of the tick on either side of the axis line.
47
     *
48
     * @method setTickOffset
49
     * @protected
50
     */
51
    setTickOffsets: function()
52
    {
53
        var host = this,
54
            majorTicks = host.get("styles").majorTicks,
55
            tickLength = majorTicks.length,
56
            halfTick = tickLength * 0.5,
57
            display = majorTicks.display;
58
        host.set("topTickOffset",  0);
59
        host.set("bottomTickOffset",  0);
60
 
61
        switch(display)
62
        {
63
            case "inside" :
64
                host.set("rightTickOffset",  tickLength);
65
                host.set("leftTickOffset", 0);
66
            break;
67
            case "outside" :
68
                host.set("rightTickOffset", 0);
69
                host.set("leftTickOffset",  tickLength);
70
            break;
71
            case "cross":
72
                host.set("rightTickOffset", halfTick);
73
                host.set("leftTickOffset",  halfTick);
74
            break;
75
            default:
76
                host.set("rightTickOffset", 0);
77
                host.set("leftTickOffset", 0);
78
            break;
79
        }
80
    },
81
 
82
    /**
83
     * Draws a tick
84
     *
85
     * @method drawTick
86
     * @param {Path} path reference to the path `Path` element in which to draw the tick.
87
     * @param {Object} pt Point on the axis in which the tick will intersect.
88
     * @param {Object} tickStyle Hash of properties to apply to the tick.
89
     * @protected
90
     */
91
    drawTick: function(path, pt, tickStyles)
92
    {
93
        var host = this,
94
            style = host.get("styles"),
95
            padding = style.padding,
96
            tickLength = tickStyles.length,
97
            start = {x:padding.left, y:pt.y},
98
            end = {x:tickLength + padding.left, y:pt.y};
99
        host.drawLine(path, start, end);
100
    },
101
 
102
    /**
103
     * Calculates the coordinates for the first point on an axis.
104
     *
105
     * @method getLineStart
106
     * @return {Object}
107
     * @protected
108
     */
109
    getLineStart: function()
110
    {
111
        var style = this.get("styles"),
112
            padding = style.padding,
113
            majorTicks = style.majorTicks,
114
            tickLength = majorTicks.length,
115
            display = majorTicks.display,
116
            pt = {x:padding.left, y:0};
117
        if(display === "outside")
118
        {
119
            pt.x += tickLength;
120
        }
121
        else if(display === "cross")
122
        {
123
            pt.x += tickLength/2;
124
        }
125
        return pt;
126
    },
127
 
128
    /**
129
     * Calculates the point for a label.
130
     *
131
     * @method getLabelPoint
132
     * @param {Object} point Point on the axis in which the tick will intersect.
133
     * @return {Object}
134
     * @protected
135
     */
136
    getLabelPoint: function(point)
137
    {
138
        return {x:point.x - this.get("leftTickOffset"), y:point.y};
139
    },
140
 
141
    /**
142
     * Updates the value for the `maxLabelSize` for use in calculating total size.
143
     *
144
     * @method updateMaxLabelSize
145
     * @param {HTMLElement} label to measure
146
     * @protected
147
     */
148
    updateMaxLabelSize: function(labelWidth, labelHeight)
149
    {
150
        var host = this,
151
            props = this._labelRotationProps,
152
            rot = props.rot,
153
            absRot = props.absRot,
154
            sinRadians = props.sinRadians,
155
            cosRadians = props.cosRadians,
156
            max;
157
        if(rot === 0)
158
        {
159
            max = labelWidth;
160
        }
161
        else if(absRot === 90)
162
        {
163
            max = labelHeight;
164
        }
165
        else
166
        {
167
            max = (cosRadians * labelWidth) + (sinRadians * labelHeight);
168
        }
169
        host._maxLabelSize = Math.max(host._maxLabelSize, max);
170
    },
171
 
172
    /**
173
     * Determines the available label width when the axis width has been explicitly set.
174
     *
175
     * @method getExplicitlySized
176
     * @return Boolean
177
     * @protected
178
     */
179
    getExplicitlySized: function(styles)
180
    {
181
        if(this._explicitWidth)
182
        {
183
            var host = this,
184
                w = host._explicitWidth,
185
                totalTitleSize = host._totalTitleSize,
186
                leftTickOffset = host.get("leftTickOffset"),
187
                margin = styles.label.margin.right;
188
            host._maxLabelSize =  w - (leftTickOffset + margin + totalTitleSize);
189
            return true;
190
        }
191
        return false;
192
    },
193
 
194
    /**
195
     * Rotate and position title.
196
     *
197
     * @method positionTitle
198
     * @param {HTMLElement} label to rotate position
199
     * @protected
200
     */
201
    positionTitle: function(label)
202
    {
203
        var host = this,
204
            bounds = host._titleBounds,
205
            margin = host.get("styles").title.margin,
206
            props = host._titleRotationProps,
207
            w = bounds.right - bounds.left,
208
            labelWidth = label.offsetWidth,
209
            labelHeight = label.offsetHeight,
210
            x = (labelWidth * -0.5) + (w * 0.5),
211
            y = (host.get("height") * 0.5) - (labelHeight * 0.5);
212
        props.labelWidth = labelWidth;
213
        props.labelHeight = labelHeight;
214
        if(margin && margin.left)
215
        {
216
            x += margin.left;
217
        }
218
        props.x = x;
219
        props.y = y;
220
        props.transformOrigin = [0.5, 0.5];
221
        host._rotate(label, props);
222
    },
223
 
224
    /**
225
     * Rotate and position labels.
226
     *
227
     * @method positionLabel
228
     * @param {HTMLElement} label to rotate position
229
     * @param {Object} pt hash containing the x and y coordinates in which the label will be positioned
230
     * against.
231
     * @protected
232
     */
233
    positionLabel: function(label, pt, styles, i)
234
    {
235
        var host = this,
236
            offset = parseFloat(styles.label.offset),
237
            tickOffset = host.get("leftTickOffset"),
238
            totalTitleSize = this._totalTitleSize,
239
            leftOffset = pt.x + totalTitleSize - tickOffset,
240
            topOffset = pt.y,
241
            props = this._labelRotationProps,
242
            rot = props.rot,
243
            absRot = props.absRot,
244
            maxLabelSize = host._maxLabelSize,
245
            labelWidth = this._labelWidths[i],
246
            labelHeight = this._labelHeights[i];
247
        if(rot === 0)
248
        {
249
            leftOffset -= labelWidth;
250
            topOffset -= labelHeight * offset;
251
        }
252
        else if(rot === 90)
253
        {
254
            leftOffset -= labelWidth * 0.5;
255
            topOffset = topOffset + labelWidth/2 - (labelWidth * offset);
256
        }
257
        else if(rot === -90)
258
        {
259
            leftOffset -= labelWidth * 0.5;
260
            topOffset = topOffset - labelHeight + labelWidth/2 - (labelWidth * offset);
261
        }
262
        else
263
        {
264
            leftOffset -= labelWidth + (labelHeight * absRot/360);
265
            topOffset -= labelHeight * offset;
266
        }
267
        props.labelWidth = labelWidth;
268
        props.labelHeight = labelHeight;
269
        props.x = Math.round(maxLabelSize + leftOffset);
270
        props.y = Math.round(topOffset);
271
        this._rotate(label, props);
272
    },
273
 
274
    /**
275
     * Adjusts the coordinates of an axis label based on the rotation.
276
     *
277
     * @method _setRotationCoords
278
     * @param {Object} props Coordinates, dimension and rotation properties of the label.
279
     * @protected
280
     */
281
    _setRotationCoords: function(props)
282
    {
283
        var rot = props.rot,
284
            absRot = props.absRot,
285
            leftOffset,
286
            topOffset,
287
            labelWidth = props.labelWidth,
288
            labelHeight = props.labelHeight;
289
        if(rot === 0)
290
        {
291
            leftOffset = labelWidth;
292
            topOffset = labelHeight * 0.5;
293
        }
294
        else if(rot === 90)
295
        {
296
            topOffset = 0;
297
            leftOffset = labelWidth * 0.5;
298
        }
299
        else if(rot === -90)
300
        {
301
            leftOffset = labelWidth * 0.5;
302
            topOffset = labelHeight;
303
        }
304
        else
305
        {
306
            leftOffset = labelWidth + (labelHeight * absRot/360);
307
            topOffset = labelHeight * 0.5;
308
        }
309
        props.x -= leftOffset;
310
        props.y -= topOffset;
311
    },
312
 
313
    /**
314
     * Returns the transformOrigin to use for an axis label based on the position of the axis
315
     * and the rotation of the label.
316
     *
317
     * @method _getTransformOrigin
318
     * @param {Number} rot The rotation (in degrees) of the label.
319
     * @return Array
320
     * @protected
321
     */
322
    _getTransformOrigin: function(rot)
323
    {
324
        var transformOrigin;
325
        if(rot === 0)
326
        {
327
            transformOrigin = [0, 0];
328
        }
329
        else if(rot === 90)
330
        {
331
            transformOrigin = [0.5, 0];
332
        }
333
        else if(rot === -90)
334
        {
335
            transformOrigin = [0.5, 1];
336
        }
337
        else
338
        {
339
            transformOrigin = [1, 0.5];
340
        }
341
        return transformOrigin;
342
    },
343
 
344
    /**
345
     * Adjust the position of the Axis widget's content box for internal axes.
346
     *
347
     * @method offsetNodeForTick
348
     * @param {Node} cb contentBox of the axis
349
     * @protected
350
     */
351
    offsetNodeForTick: function()
352
    {
353
    },
354
 
355
    /**
356
     * Sets the width of the axis based on its contents.
357
     *
358
     * @method setCalculatedSize
359
     * @protected
360
     */
361
    setCalculatedSize: function()
362
    {
363
        var host = this,
364
            graphic = this.get("graphic"),
365
            style = host.get("styles"),
366
            label = style.label,
367
            tickOffset = host.get("leftTickOffset"),
368
            max = host._maxLabelSize,
369
            totalTitleSize = this._totalTitleSize,
370
            ttl = Math.round(totalTitleSize + tickOffset + max + label.margin.right);
371
        if(this._explicitWidth)
372
        {
373
            ttl = this._explicitWidth;
374
        }
375
        this.set("calculatedWidth", ttl);
376
        graphic.set("x", ttl - tickOffset);
377
    }
378
};
379
 
380
Y.LeftAxisLayout = LeftAxisLayout;
381
/**
382
 * RightAxisLayout contains algorithms for rendering a right axis.
383
 *
384
 * @class RightAxisLayout
385
 * @constructor
386
 * @submodule axis
387
 */
388
RightAxisLayout = function(){};
389
 
390
RightAxisLayout.prototype = {
391
    /**
392
     *  Default margins for text fields.
393
     *
394
     *  @private
395
     *  @method _getDefaultMargins
396
     *  @return Object
397
     */
398
    _getDefaultMargins: function()
399
    {
400
        return {
401
            top: 0,
402
            left: 4,
403
            right: 0,
404
            bottom: 0
405
        };
406
    },
407
 
408
    /**
409
     * Sets the length of the tick on either side of the axis line.
410
     *
411
     * @method setTickOffset
412
     * @protected
413
     */
414
    setTickOffsets: function()
415
    {
416
        var host = this,
417
            majorTicks = host.get("styles").majorTicks,
418
            tickLength = majorTicks.length,
419
            halfTick = tickLength * 0.5,
420
            display = majorTicks.display;
421
        host.set("topTickOffset",  0);
422
        host.set("bottomTickOffset",  0);
423
 
424
        switch(display)
425
        {
426
            case "inside" :
427
                host.set("leftTickOffset", tickLength);
428
                host.set("rightTickOffset", 0);
429
            break;
430
            case "outside" :
431
                host.set("leftTickOffset", 0);
432
                host.set("rightTickOffset", tickLength);
433
            break;
434
            case "cross" :
435
                host.set("rightTickOffset", halfTick);
436
                host.set("leftTickOffset", halfTick);
437
            break;
438
            default:
439
                host.set("leftTickOffset", 0);
440
                host.set("rightTickOffset", 0);
441
            break;
442
        }
443
    },
444
 
445
    /**
446
     * Draws a tick
447
     *
448
     * @method drawTick
449
     * @param {Path} path reference to the path `Path` element in which to draw the tick.
450
     * @param {Object} pt Point on the axis in which the tick will intersect.
451
     * @param {Object} tickStyle Hash of properties to apply to the tick.
452
     * @protected
453
     */
454
    drawTick: function(path, pt, tickStyles)
455
    {
456
        var host = this,
457
            style = host.get("styles"),
458
            padding = style.padding,
459
            tickLength = tickStyles.length,
460
            start = {x:padding.left, y:pt.y},
461
            end = {x:padding.left + tickLength, y:pt.y};
462
        host.drawLine(path, start, end);
463
    },
464
 
465
    /**
466
     * Calculates the coordinates for the first point on an axis.
467
     *
468
     * @method getLineStart
469
     * @return {Object}
470
     * @protected
471
     */
472
    getLineStart: function()
473
    {
474
        var host = this,
475
            style = host.get("styles"),
476
            padding = style.padding,
477
            majorTicks = style.majorTicks,
478
            tickLength = majorTicks.length,
479
            display = majorTicks.display,
480
            pt = {x:padding.left, y:padding.top};
481
        if(display === "inside")
482
        {
483
            pt.x += tickLength;
484
        }
485
        else if(display === "cross")
486
        {
487
            pt.x += tickLength/2;
488
        }
489
        return pt;
490
    },
491
 
492
    /**
493
     * Calculates the point for a label.
494
     *
495
     * @method getLabelPoint
496
     * @param {Object} point Point on the axis in which the tick will intersect.
497
     * @return {Object}
498
     * @protected
499
     */
500
    getLabelPoint: function(point)
501
    {
502
        return {x:point.x + this.get("rightTickOffset"), y:point.y};
503
    },
504
 
505
    /**
506
     * Updates the value for the `maxLabelSize` for use in calculating total size.
507
     *
508
     * @method updateMaxLabelSize
509
     * @param {HTMLElement} label to measure
510
     * @protected
511
     */
512
    updateMaxLabelSize: function(labelWidth, labelHeight)
513
    {
514
        var host = this,
515
            props = this._labelRotationProps,
516
            rot = props.rot,
517
            absRot = props.absRot,
518
            sinRadians = props.sinRadians,
519
            cosRadians = props.cosRadians,
520
            max;
521
        if(rot === 0)
522
        {
523
            max = labelWidth;
524
        }
525
        else if(absRot === 90)
526
        {
527
            max = labelHeight;
528
        }
529
        else
530
        {
531
            max = (cosRadians * labelWidth) + (sinRadians * labelHeight);
532
        }
533
        host._maxLabelSize = Math.max(host._maxLabelSize, max);
534
    },
535
 
536
    /**
537
     * Determines the available label width when the axis width has been explicitly set.
538
     *
539
     * @method getExplicitlySized
540
     * @return Boolean
541
     * @protected
542
     */
543
    getExplicitlySized: function(styles)
544
    {
545
        if(this._explicitWidth)
546
        {
547
            var host = this,
548
                w = host._explicitWidth,
549
                totalTitleSize = this._totalTitleSize,
550
                rightTickOffset = host.get("rightTickOffset"),
551
                margin = styles.label.margin.right;
552
            host._maxLabelSize =  w - (rightTickOffset + margin + totalTitleSize);
553
            return true;
554
        }
555
        return false;
556
    },
557
 
558
    /**
559
     * Rotate and position title.
560
     *
561
     * @method positionTitle
562
     * @param {HTMLElement} label to rotate position
563
     * @protected
564
     */
565
    positionTitle: function(label)
566
    {
567
        var host = this,
568
            bounds = host._titleBounds,
569
            margin = host.get("styles").title.margin,
570
            props = host._titleRotationProps,
571
            labelWidth = label.offsetWidth,
572
            labelHeight = label.offsetHeight,
573
            w = bounds.right - bounds.left,
574
            x = this.get("width") - (labelWidth * 0.5) - (w * 0.5),
575
            y = (host.get("height") * 0.5) - (labelHeight * 0.5);
576
        props.labelWidth = labelWidth;
577
        props.labelHeight = labelHeight;
578
        if(margin && margin.right)
579
        {
580
            x -= margin.left;
581
        }
582
        props.x = x;
583
        props.y = y;
584
        props.transformOrigin = [0.5, 0.5];
585
        host._rotate(label, props);
586
    },
587
 
588
    /**
589
     * Rotate and position labels.
590
     *
591
     * @method positionLabel
592
     * @param {HTMLElement} label to rotate position
593
     * @param {Object} pt hash containing the x and y coordinates in which the label will be positioned
594
     * against.
595
     * @protected
596
     */
597
    positionLabel: function(label, pt, styles, i)
598
    {
599
        var host = this,
600
            offset = parseFloat(styles.label.offset),
601
            tickOffset = host.get("rightTickOffset"),
602
            labelStyles = styles.label,
603
            margin = 0,
604
            leftOffset = pt.x,
605
            topOffset = pt.y,
606
            props = this._labelRotationProps,
607
            rot = props.rot,
608
            absRot = props.absRot,
609
            labelWidth = this._labelWidths[i],
610
            labelHeight = this._labelHeights[i];
611
        if(labelStyles.margin && labelStyles.margin.left)
612
        {
613
            margin = labelStyles.margin.left;
614
        }
615
        if(rot === 0)
616
        {
617
            topOffset -= labelHeight * offset;
618
        }
619
        else if(rot === 90)
620
        {
621
            leftOffset -= labelWidth * 0.5;
622
            topOffset = topOffset - labelHeight + labelWidth/2 - (labelWidth * offset);
623
        }
624
        else if(rot === -90)
625
        {
626
            topOffset = topOffset + labelWidth/2 - (labelWidth * offset);
627
            leftOffset -= labelWidth * 0.5;
628
        }
629
        else
630
        {
631
            topOffset -= labelHeight * offset;
632
            leftOffset += labelHeight/2 * absRot/90;
633
        }
634
        leftOffset += margin;
635
        leftOffset += tickOffset;
636
        props.labelWidth = labelWidth;
637
        props.labelHeight = labelHeight;
638
        props.x = Math.round(leftOffset);
639
        props.y = Math.round(topOffset);
640
        this._rotate(label, props);
641
    },
642
 
643
    /**
644
     * Adjusts the coordinates of an axis label based on the rotation.
645
     *
646
     * @method _setRotationCoords
647
     * @param {Object} props Coordinates, dimension and rotation properties of the label.
648
     * @protected
649
     */
650
    _setRotationCoords: function(props)
651
    {
652
        var rot = props.rot,
653
            absRot = props.absRot,
654
            leftOffset = 0,
655
            topOffset = 0,
656
            labelWidth = props.labelWidth,
657
            labelHeight = props.labelHeight;
658
        if(rot === 0)
659
        {
660
            topOffset = labelHeight * 0.5;
661
        }
662
        else if(rot === 90)
663
        {
664
            leftOffset = labelWidth * 0.5;
665
            topOffset = labelHeight;
666
        }
667
        else if(rot === -90)
668
        {
669
            leftOffset = labelWidth * 0.5;
670
        }
671
        else
672
        {
673
            topOffset = labelHeight * 0.5;
674
            leftOffset = labelHeight/2 * absRot/90;
675
        }
676
        props.x -= leftOffset;
677
        props.y -= topOffset;
678
    },
679
 
680
    /**
681
     * Returns the transformOrigin to use for an axis label based on the position of the axis
682
     * and the rotation of the label.
683
     *
684
     * @method _getTransformOrigin
685
     * @param {Number} rot The rotation (in degrees) of the label.
686
     * @return Array
687
     * @protected
688
     */
689
    _getTransformOrigin: function(rot)
690
    {
691
        var transformOrigin;
692
        if(rot === 0)
693
        {
694
            transformOrigin = [0, 0];
695
        }
696
        else if(rot === 90)
697
        {
698
            transformOrigin = [0.5, 1];
699
        }
700
        else if(rot === -90)
701
        {
702
            transformOrigin = [0.5, 0];
703
        }
704
        else
705
        {
706
            transformOrigin = [0, 0.5];
707
        }
708
        return transformOrigin;
709
    },
710
 
711
    /**
712
     * Adjusts position for inner ticks.
713
     *
714
     * @method offsetNodeForTick
715
     * @param {Node} cb contentBox of the axis
716
     * @protected
717
     */
718
    offsetNodeForTick: function(cb)
719
    {
720
        var host = this,
721
            tickOffset = host.get("leftTickOffset"),
722
            offset = 0 - tickOffset;
723
        cb.setStyle("left", offset);
724
    },
725
 
726
    /**
727
     * Assigns a height based on the size of the contents.
728
     *
729
     * @method setCalculatedSize
730
     * @protected
731
     */
732
    setCalculatedSize: function()
733
    {
734
        var host = this,
735
            styles = host.get("styles"),
736
            labelStyle = styles.label,
737
            totalTitleSize = this._totalTitleSize,
738
            ttl = Math.round(host.get("rightTickOffset") + host._maxLabelSize + totalTitleSize + labelStyle.margin.left);
739
        if(this._explicitWidth)
740
        {
741
            ttl = this._explicitWidth;
742
        }
743
        host.set("calculatedWidth", ttl);
744
        host.get("contentBox").setStyle("width", ttl);
745
    }
746
};
747
 
748
Y.RightAxisLayout = RightAxisLayout;
749
/**
750
 * Contains algorithms for rendering a bottom axis.
751
 *
752
 * @class BottomAxisLayout
753
 * @Constructor
754
 * @submodule axis
755
 */
756
BottomAxisLayout = function(){};
757
 
758
BottomAxisLayout.prototype = {
759
    /**
760
     *  Default margins for text fields.
761
     *
762
     *  @private
763
     *  @method _getDefaultMargins
764
     *  @return Object
765
     */
766
    _getDefaultMargins: function()
767
    {
768
        return {
769
            top: 4,
770
            left: 0,
771
            right: 0,
772
            bottom: 0
773
        };
774
    },
775
 
776
    /**
777
     * Sets the length of the tick on either side of the axis line.
778
     *
779
     * @method setTickOffsets
780
     * @protected
781
     */
782
    setTickOffsets: function()
783
    {
784
        var host = this,
785
            majorTicks = host.get("styles").majorTicks,
786
            tickLength = majorTicks.length,
787
            halfTick = tickLength * 0.5,
788
            display = majorTicks.display;
789
        host.set("leftTickOffset",  0);
790
        host.set("rightTickOffset",  0);
791
 
792
        switch(display)
793
        {
794
            case "inside" :
795
                host.set("topTickOffset", tickLength);
796
                host.set("bottomTickOffset", 0);
797
            break;
798
            case "outside" :
799
                host.set("topTickOffset", 0);
800
                host.set("bottomTickOffset", tickLength);
801
            break;
802
            case "cross":
803
                host.set("topTickOffset",  halfTick);
804
                host.set("bottomTickOffset",  halfTick);
805
            break;
806
            default:
807
                host.set("topTickOffset", 0);
808
                host.set("bottomTickOffset", 0);
809
            break;
810
        }
811
    },
812
 
813
    /**
814
     * Calculates the coordinates for the first point on an axis.
815
     *
816
     * @method getLineStart
817
     * @protected
818
     */
819
    getLineStart: function()
820
    {
821
        var style = this.get("styles"),
822
            padding = style.padding,
823
            majorTicks = style.majorTicks,
824
            tickLength = majorTicks.length,
825
            display = majorTicks.display,
826
            pt = {x:0, y:padding.top};
827
        if(display === "inside")
828
        {
829
            pt.y += tickLength;
830
        }
831
        else if(display === "cross")
832
        {
833
            pt.y += tickLength/2;
834
        }
835
        return pt;
836
    },
837
 
838
    /**
839
     * Draws a tick
840
     *
841
     * @method drawTick
842
     * @param {Path} path reference to the path `Path` element in which to draw the tick.
843
     * @param {Object} pt hash containing x and y coordinates
844
     * @param {Object} tickStyles hash of properties used to draw the tick
845
     * @protected
846
     */
847
    drawTick: function(path, pt, tickStyles)
848
    {
849
        var host = this,
850
            style = host.get("styles"),
851
            padding = style.padding,
852
            tickLength = tickStyles.length,
853
            start = {x:pt.x, y:padding.top},
854
            end = {x:pt.x, y:tickLength + padding.top};
855
        host.drawLine(path, start, end);
856
    },
857
 
858
    /**
859
     * Calculates the point for a label.
860
     *
861
     * @method getLabelPoint
862
     * @param {Object} pt Object containing x and y coordinates
863
     * @return Object
864
     * @protected
865
     */
866
    getLabelPoint: function(point)
867
    {
868
        return {x:point.x, y:point.y + this.get("bottomTickOffset")};
869
    },
870
 
871
    /**
872
     * Updates the value for the `maxLabelSize` for use in calculating total size.
873
     *
874
     * @method updateMaxLabelSize
875
     * @param {HTMLElement} label to measure
876
     * @protected
877
     */
878
    updateMaxLabelSize: function(labelWidth, labelHeight)
879
    {
880
        var host = this,
881
            props = this._labelRotationProps,
882
            rot = props.rot,
883
            absRot = props.absRot,
884
            sinRadians = props.sinRadians,
885
            cosRadians = props.cosRadians,
886
            max;
887
        if(rot === 0)
888
        {
889
            max = labelHeight;
890
        }
891
        else if(absRot === 90)
892
        {
893
            max = labelWidth;
894
        }
895
        else
896
        {
897
            max = (sinRadians * labelWidth) + (cosRadians * labelHeight);
898
        }
899
        host._maxLabelSize = Math.max(host._maxLabelSize, max);
900
    },
901
 
902
    /**
903
     * Determines the available label height when the axis width has been explicitly set.
904
     *
905
     * @method getExplicitlySized
906
     * @return Boolean
907
     * @protected
908
     */
909
    getExplicitlySized: function(styles)
910
    {
911
        if(this._explicitHeight)
912
        {
913
            var host = this,
914
                h = host._explicitHeight,
915
                totalTitleSize = host._totalTitleSize,
916
                bottomTickOffset = host.get("bottomTickOffset"),
917
                margin = styles.label.margin.right;
918
            host._maxLabelSize =  h - (bottomTickOffset + margin + totalTitleSize);
919
            return true;
920
        }
921
        return false;
922
    },
923
 
924
    /**
925
     * Rotate and position title.
926
     *
927
     * @method positionTitle
928
     * @param {HTMLElement} label to rotate position
929
     * @protected
930
     */
931
    positionTitle: function(label)
932
    {
933
        var host = this,
934
            bounds = host._titleBounds,
935
            margin = host.get("styles").title.margin,
936
            props = host._titleRotationProps,
937
            h = bounds.bottom - bounds.top,
938
            labelWidth = label.offsetWidth,
939
            labelHeight = label.offsetHeight,
940
            x = (host.get("width") * 0.5) - (labelWidth * 0.5),
941
            y = host.get("height") - labelHeight/2 - h/2;
942
        props.labelWidth = labelWidth;
943
        props.labelHeight = labelHeight;
944
        if(margin && margin.bottom)
945
        {
946
            y -= margin.bottom;
947
        }
948
        props.x = x;
949
        props.y = y;
950
        props.transformOrigin = [0.5, 0.5];
951
        host._rotate(label, props);
952
    },
953
 
954
    /**
955
     * Rotate and position labels.
956
     *
957
     * @method positionLabel
958
     * @param {HTMLElement} label to rotate position
959
     * @param {Object} pt hash containing the x and y coordinates in which the label will be positioned
960
     * against.
961
     * @protected
962
     */
963
    positionLabel: function(label, pt, styles, i)
964
    {
965
        var host = this,
966
            offset = parseFloat(styles.label.offset),
967
            tickOffset = host.get("bottomTickOffset"),
968
            labelStyles = styles.label,
969
            margin = 0,
970
            props = host._labelRotationProps,
971
            rot = props.rot,
972
            absRot = props.absRot,
973
            leftOffset = Math.round(pt.x),
974
            topOffset = Math.round(pt.y),
975
            labelWidth = host._labelWidths[i],
976
            labelHeight = host._labelHeights[i];
977
        if(labelStyles.margin && labelStyles.margin.top)
978
        {
979
            margin = labelStyles.margin.top;
980
        }
981
        if(rot === 90)
982
        {
983
            topOffset -= labelHeight/2 * rot/90;
984
            leftOffset = leftOffset + labelHeight/2 - (labelHeight * offset);
985
        }
986
        else if(rot === -90)
987
        {
988
            topOffset -= labelHeight/2 * absRot/90;
989
            leftOffset = leftOffset - labelWidth + labelHeight/2 - (labelHeight * offset);
990
        }
991
        else if(rot > 0)
992
        {
993
            leftOffset = leftOffset + labelHeight/2 - (labelHeight * offset);
994
            topOffset -= labelHeight/2 * rot/90;
995
        }
996
        else if(rot < 0)
997
        {
998
            leftOffset = leftOffset - labelWidth + labelHeight/2 - (labelHeight * offset);
999
            topOffset -= labelHeight/2 * absRot/90;
1000
        }
1001
        else
1002
        {
1003
            leftOffset -= labelWidth * offset;
1004
        }
1005
        topOffset += margin;
1006
        topOffset += tickOffset;
1007
        props.labelWidth = labelWidth;
1008
        props.labelHeight = labelHeight;
1009
        props.x = leftOffset;
1010
        props.y = topOffset;
1011
        host._rotate(label, props);
1012
    },
1013
 
1014
    /**
1015
     * Adjusts the coordinates of an axis label based on the rotation.
1016
     *
1017
     * @method _setRotationCoords
1018
     * @param {Object} props Coordinates, dimension and rotation properties of the label.
1019
     * @protected
1020
     */
1021
    _setRotationCoords: function(props)
1022
    {
1023
        var rot = props.rot,
1024
            absRot = props.absRot,
1025
            labelWidth = props.labelWidth,
1026
            labelHeight = props.labelHeight,
1027
            leftOffset,
1028
            topOffset;
1029
 
1030
        if(rot > 0)
1031
        {
1032
            leftOffset = 0;
1033
            topOffset = labelHeight/2 * rot/90;
1034
        }
1035
        else if(rot < 0)
1036
        {
1037
            leftOffset = labelWidth;
1038
            topOffset = labelHeight/2 * absRot/90;
1039
        }
1040
        else
1041
        {
1042
            leftOffset = labelWidth * 0.5;
1043
            topOffset = 0;
1044
        }
1045
        props.x -= leftOffset;
1046
        props.y -= topOffset;
1047
    },
1048
 
1049
    /**
1050
     * Returns the transformOrigin to use for an axis label based on the position of the axis
1051
     * and the rotation of the label.
1052
     *
1053
     * @method _getTransformOrigin
1054
     * @param {Number} rot The rotation (in degrees) of the label.
1055
     * @return Array
1056
     * @protected
1057
     */
1058
    _getTransformOrigin: function(rot)
1059
    {
1060
        var transformOrigin;
1061
        if(rot > 0)
1062
        {
1063
            transformOrigin = [0, 0.5];
1064
        }
1065
        else if(rot < 0)
1066
        {
1067
            transformOrigin = [1, 0.5];
1068
        }
1069
        else
1070
        {
1071
            transformOrigin = [0, 0];
1072
        }
1073
        return transformOrigin;
1074
    },
1075
 
1076
    /**
1077
     * Adjusts position for inner ticks.
1078
     *
1079
     * @method offsetNodeForTick
1080
     * @param {Node} cb contentBox of the axis
1081
     * @protected
1082
     */
1083
    offsetNodeForTick: function(cb)
1084
    {
1085
        var host = this;
1086
        cb.setStyle("top", 0 - host.get("topTickOffset"));
1087
    },
1088
 
1089
    /**
1090
     * Assigns a height based on the size of the contents.
1091
     *
1092
     * @method setCalculatedSize
1093
     * @protected
1094
     */
1095
    setCalculatedSize: function()
1096
    {
1097
        var host = this,
1098
            styles = host.get("styles"),
1099
            labelStyle = styles.label,
1100
            totalTitleSize = host._totalTitleSize,
1101
            ttl = Math.round(host.get("bottomTickOffset") + host._maxLabelSize + labelStyle.margin.top + totalTitleSize);
1102
        if(host._explicitHeight)
1103
        {
1104
            ttl = host._explicitHeight;
1105
        }
1106
        host.set("calculatedHeight", ttl);
1107
    }
1108
};
1109
Y.BottomAxisLayout = BottomAxisLayout;
1110
/**
1111
 * Contains algorithms for rendering a top axis.
1112
 *
1113
 * @class TopAxisLayout
1114
 * @constructor
1115
 * @submodule axis
1116
 */
1117
TopAxisLayout = function(){};
1118
 
1119
TopAxisLayout.prototype = {
1120
    /**
1121
     *  Default margins for text fields.
1122
     *
1123
     *  @private
1124
     *  @method _getDefaultMargins
1125
     *  @return Object
1126
     */
1127
    _getDefaultMargins: function()
1128
    {
1129
        return {
1130
            top: 0,
1131
            left: 0,
1132
            right: 0,
1133
            bottom: 4
1134
        };
1135
    },
1136
 
1137
    /**
1138
     * Sets the length of the tick on either side of the axis line.
1139
     *
1140
     * @method setTickOffsets
1141
     * @protected
1142
     */
1143
    setTickOffsets: function()
1144
    {
1145
        var host = this,
1146
            majorTicks = host.get("styles").majorTicks,
1147
            tickLength = majorTicks.length,
1148
            halfTick = tickLength * 0.5,
1149
            display = majorTicks.display;
1150
        host.set("leftTickOffset",  0);
1151
        host.set("rightTickOffset",  0);
1152
        switch(display)
1153
        {
1154
            case "inside" :
1155
                host.set("bottomTickOffset", tickLength);
1156
                host.set("topTickOffset", 0);
1157
            break;
1158
            case "outside" :
1159
                host.set("bottomTickOffset", 0);
1160
                host.set("topTickOffset",  tickLength);
1161
            break;
1162
            case "cross" :
1163
                host.set("topTickOffset", halfTick);
1164
                host.set("bottomTickOffset", halfTick);
1165
            break;
1166
            default:
1167
                host.set("topTickOffset", 0);
1168
                host.set("bottomTickOffset", 0);
1169
            break;
1170
        }
1171
    },
1172
 
1173
    /**
1174
     * Calculates the coordinates for the first point on an axis.
1175
     *
1176
     * @method getLineStart
1177
     * @protected
1178
     */
1179
    getLineStart: function()
1180
    {
1181
        var host = this,
1182
            style = host.get("styles"),
1183
            padding = style.padding,
1184
            majorTicks = style.majorTicks,
1185
            tickLength = majorTicks.length,
1186
            display = majorTicks.display,
1187
            pt = {x:0, y:padding.top};
1188
        if(display === "outside")
1189
        {
1190
            pt.y += tickLength;
1191
        }
1192
        else if(display === "cross")
1193
        {
1194
            pt.y += tickLength/2;
1195
        }
1196
        return pt;
1197
    },
1198
 
1199
    /**
1200
     * Draws a tick
1201
     *
1202
     * @method drawTick
1203
     * @param {Path} path reference to the path `Path` element in which to draw the tick.
1204
     * @param {Object} pt hash containing x and y coordinates
1205
     * @param {Object} tickStyles hash of properties used to draw the tick
1206
     * @protected
1207
     */
1208
    drawTick: function(path, pt, tickStyles)
1209
    {
1210
        var host = this,
1211
            style = host.get("styles"),
1212
            padding = style.padding,
1213
            tickLength = tickStyles.length,
1214
            start = {x:pt.x, y:padding.top},
1215
            end = {x:pt.x, y:tickLength + padding.top};
1216
        host.drawLine(path, start, end);
1217
    },
1218
 
1219
    /**
1220
     * Calculates the point for a label.
1221
     *
1222
     * @method getLabelPoint
1223
     * @param {Object} pt hash containing x and y coordinates
1224
     * @return Object
1225
     * @protected
1226
     */
1227
    getLabelPoint: function(pt)
1228
    {
1229
        return {x:pt.x, y:pt.y - this.get("topTickOffset")};
1230
    },
1231
 
1232
    /**
1233
     * Updates the value for the `maxLabelSize` for use in calculating total size.
1234
     *
1235
     * @method updateMaxLabelSize
1236
     * @param {HTMLElement} label to measure
1237
     * @protected
1238
     */
1239
    updateMaxLabelSize: function(labelWidth, labelHeight)
1240
    {
1241
        var host = this,
1242
            props = this._labelRotationProps,
1243
            rot = props.rot,
1244
            absRot = props.absRot,
1245
            sinRadians = props.sinRadians,
1246
            cosRadians = props.cosRadians,
1247
            max;
1248
        if(rot === 0)
1249
        {
1250
            max = labelHeight;
1251
        }
1252
        else if(absRot === 90)
1253
        {
1254
            max = labelWidth;
1255
        }
1256
        else
1257
        {
1258
            max = (sinRadians * labelWidth) + (cosRadians * labelHeight);
1259
        }
1260
        host._maxLabelSize = Math.max(host._maxLabelSize, max);
1261
    },
1262
 
1263
    /**
1264
     * Determines the available label height when the axis width has been explicitly set.
1265
     *
1266
     * @method getExplicitlySized
1267
     * @return Boolean
1268
     * @protected
1269
     */
1270
    getExplicitlySized: function(styles)
1271
    {
1272
        if(this._explicitHeight)
1273
        {
1274
            var host = this,
1275
                h = host._explicitHeight,
1276
                totalTitleSize = host._totalTitleSize,
1277
                topTickOffset = host.get("topTickOffset"),
1278
                margin = styles.label.margin.right;
1279
            host._maxLabelSize =  h - (topTickOffset + margin + totalTitleSize);
1280
            return true;
1281
        }
1282
        return false;
1283
    },
1284
 
1285
    /**
1286
     * Rotate and position title.
1287
     *
1288
     * @method positionTitle
1289
     * @param {HTMLElement} label to rotate position
1290
     * @protected
1291
     */
1292
    positionTitle: function(label)
1293
    {
1294
        var host = this,
1295
            bounds = host._titleBounds,
1296
            margin = host.get("styles").title.margin,
1297
            props = host._titleRotationProps,
1298
            labelWidth = label.offsetWidth,
1299
            labelHeight = label.offsetHeight,
1300
            h = bounds.bottom - bounds.top,
1301
            x = (host.get("width") * 0.5) - (labelWidth * 0.5),
1302
            y = h/2 - labelHeight/2;
1303
        props.labelWidth = labelWidth;
1304
        props.labelHeight = labelHeight;
1305
        if(margin && margin.top)
1306
        {
1307
            y += margin.top;
1308
        }
1309
        props.x = x;
1310
        props.y = y;
1311
        props.transformOrigin = [0.5, 0.5];
1312
        host._rotate(label, props);
1313
    },
1314
 
1315
    /**
1316
     * Rotate and position labels.
1317
     *
1318
     * @method positionLabel
1319
     * @param {HTMLElement} label to rotate position
1320
     * @param {Object} pt hash containing the x and y coordinates in which the label will be positioned
1321
     * against.
1322
     * @protected
1323
     */
1324
    positionLabel: function(label, pt, styles, i)
1325
    {
1326
        var host = this,
1327
            offset = parseFloat(styles.label.offset),
1328
            totalTitleSize = this._totalTitleSize,
1329
            maxLabelSize = host._maxLabelSize,
1330
            leftOffset = pt.x,
1331
            topOffset = pt.y + totalTitleSize + maxLabelSize,
1332
            props = this._labelRotationProps,
1333
            rot = props.rot,
1334
            absRot = props.absRot,
1335
            labelWidth = this._labelWidths[i],
1336
            labelHeight = this._labelHeights[i];
1337
        if(rot === 0)
1338
        {
1339
            leftOffset -= labelWidth * offset;
1340
            topOffset -= labelHeight;
1341
        }
1342
        else
1343
        {
1344
            if(rot === 90)
1345
            {
1346
                leftOffset = leftOffset - labelWidth + labelHeight/2 - (labelHeight * offset);
1347
                topOffset -= (labelHeight * 0.5);
1348
            }
1349
            else if (rot === -90)
1350
            {
1351
                leftOffset = leftOffset + labelHeight/2 - (labelHeight * offset);
1352
                topOffset -= (labelHeight * 0.5);
1353
            }
1354
            else if(rot > 0)
1355
            {
1356
                leftOffset = leftOffset - labelWidth + labelHeight/2 - (labelHeight * offset);
1357
                topOffset -= labelHeight - (labelHeight * rot/180);
1358
            }
1359
            else
1360
            {
1361
                leftOffset = leftOffset + labelHeight/2 - (labelHeight * offset);
1362
                topOffset -= labelHeight - (labelHeight * absRot/180);
1363
            }
1364
        }
1365
        props.x = Math.round(leftOffset);
1366
        props.y = Math.round(topOffset);
1367
        props.labelWidth = labelWidth;
1368
        props.labelHeight = labelHeight;
1369
        this._rotate(label, props);
1370
    },
1371
 
1372
    /**
1373
     * Adjusts the coordinates of an axis label based on the rotation.
1374
     *
1375
     * @method _setRotationCoords
1376
     * @param {Object} props Coordinates, dimension and rotation properties of the label.
1377
     * @protected
1378
     */
1379
    _setRotationCoords: function(props)
1380
    {
1381
        var rot = props.rot,
1382
            absRot = props.absRot,
1383
            labelWidth = props.labelWidth,
1384
            labelHeight = props.labelHeight,
1385
            leftOffset,
1386
            topOffset;
1387
        if(rot === 0)
1388
        {
1389
            leftOffset = labelWidth * 0.5;
1390
            topOffset = labelHeight;
1391
        }
1392
        else
1393
        {
1394
            if(rot === 90)
1395
            {
1396
                leftOffset = labelWidth;
1397
                topOffset = (labelHeight * 0.5);
1398
            }
1399
            else if (rot === -90)
1400
            {
1401
                topOffset = (labelHeight * 0.5);
1402
            }
1403
            else if(rot > 0)
1404
            {
1405
                leftOffset = labelWidth;
1406
                topOffset = labelHeight - (labelHeight * rot/180);
1407
            }
1408
            else
1409
            {
1410
                topOffset = labelHeight - (labelHeight * absRot/180);
1411
            }
1412
        }
1413
        props.x -= leftOffset;
1414
        props.y -= topOffset;
1415
    },
1416
 
1417
    /**
1418
     * Returns the transformOrigin to use for an axis label based on the position of the axis
1419
     * and the rotation of the label.
1420
     *
1421
     * @method _getTransformOrigin
1422
     * @param {Number} rot The rotation (in degrees) of the label.
1423
     * @return Array
1424
     * @protected
1425
     */
1426
    _getTransformOrigin: function(rot)
1427
    {
1428
        var transformOrigin;
1429
        if(rot === 0)
1430
        {
1431
            transformOrigin = [0, 0];
1432
        }
1433
        else
1434
        {
1435
            if(rot === 90)
1436
            {
1437
                transformOrigin = [1, 0.5];
1438
            }
1439
            else if (rot === -90)
1440
            {
1441
                transformOrigin = [0, 0.5];
1442
            }
1443
            else if(rot > 0)
1444
            {
1445
                transformOrigin = [1, 0.5];
1446
            }
1447
            else
1448
            {
1449
                transformOrigin = [0, 0.5];
1450
            }
1451
        }
1452
        return transformOrigin;
1453
    },
1454
 
1455
    /**
1456
     * Adjusts position for inner ticks.
1457
     *
1458
     * @method offsetNodeForTick
1459
     * @param {Node} cb contentBox of the axis
1460
     * @protected
1461
     */
1462
    offsetNodeForTick: function()
1463
    {
1464
    },
1465
 
1466
    /**
1467
     * Assigns a height based on the size of the contents.
1468
     *
1469
     * @method setCalculatedSize
1470
     * @protected
1471
     */
1472
    setCalculatedSize: function()
1473
    {
1474
        var host = this,
1475
            graphic = host.get("graphic"),
1476
            styles = host.get("styles"),
1477
            labelMargin = styles.label.margin,
1478
            totalLabelSize = labelMargin.bottom + host._maxLabelSize,
1479
            totalTitleSize = host._totalTitleSize,
1480
            topTickOffset = this.get("topTickOffset"),
1481
            ttl = Math.round(topTickOffset + totalLabelSize + totalTitleSize);
1482
        if(this._explicitHeight)
1483
        {
1484
           ttl = this._explicitHeight;
1485
        }
1486
        host.set("calculatedHeight", ttl);
1487
        graphic.set("y", ttl - topTickOffset);
1488
    }
1489
};
1490
Y.TopAxisLayout = TopAxisLayout;
1491
 
1492
/**
1493
 * An abstract class that provides the core functionality for draw a chart axis. Axis is used by the following classes:
1494
 * <ul>
1495
 *      <li>{{#crossLink "CategoryAxis"}}{{/crossLink}}</li>
1496
 *      <li>{{#crossLink "NumericAxis"}}{{/crossLink}}</li>
1497
 *      <li>{{#crossLink "StackedAxis"}}{{/crossLink}}</li>
1498
 *      <li>{{#crossLink "TimeAxis"}}{{/crossLink}}</li>
1499
 *  </ul>
1500
 *
1501
 * @class Axis
1502
 * @extends Widget
1503
 * @uses AxisBase
1504
 * @uses TopAxisLayout
1505
 * @uses RightAxisLayout
1506
 * @uses BottomAxisLayout
1507
 * @uses LeftAxisLayout
1508
 * @constructor
1509
 * @param {Object} config (optional) Configuration parameters.
1510
 * @submodule axis
1511
 */
1512
Y.Axis = Y.Base.create("axis", Y.Widget, [Y.AxisBase], {
1513
    /**
1514
     * Calculates and returns a value based on the number of labels and the index of
1515
     * the current label.
1516
     *
1517
     * @method getLabelByIndex
1518
     * @param {Number} i Index of the label.
1519
     * @param {Number} l Total number of labels.
1520
     * @return String
1521
     */
1522
    getLabelByIndex: function(i, l)
1523
    {
1524
        var position = this.get("position"),
1525
            direction = position === "left" || position === "right" ? "vertical" : "horizontal";
1526
        return this._getLabelByIndex(i, l, direction);
1527
    },
1528
 
1529
    /**
1530
     * @method bindUI
1531
     * @private
1532
     */
1533
    bindUI: function()
1534
    {
1535
        this.after("dataReady", Y.bind(this._dataChangeHandler, this));
1536
        this.after("dataUpdate", Y.bind(this._dataChangeHandler, this));
1537
        this.after("stylesChange", this._updateHandler);
1538
        this.after("overlapGraphChange", this._updateHandler);
1539
        this.after("positionChange", this._positionChangeHandler);
1540
        this.after("widthChange", this._handleSizeChange);
1541
        this.after("heightChange", this._handleSizeChange);
1542
        this.after("calculatedWidthChange", this._handleSizeChange);
1543
        this.after("calculatedHeightChange", this._handleSizeChange);
1544
    },
1545
    /**
1546
     * Storage for calculatedWidth value.
1547
     *
1548
     * @property _calculatedWidth
1549
     * @type Number
1550
     * @private
1551
     */
1552
    _calculatedWidth: 0,
1553
 
1554
    /**
1555
     * Storage for calculatedHeight value.
1556
     *
1557
     * @property _calculatedHeight
1558
     * @type Number
1559
     * @private
1560
     */
1561
    _calculatedHeight: 0,
1562
 
1563
    /**
1564
     * Handles change to the dataProvider
1565
     *
1566
     * @method _dataChangeHandler
1567
     * @param {Object} e Event object
1568
     * @private
1569
     */
1570
    _dataChangeHandler: function()
1571
    {
1572
        if(this.get("rendered"))
1573
        {
1574
            this._drawAxis();
1575
        }
1576
    },
1577
 
1578
    /**
1579
     * Handles change to the position attribute
1580
     *
1581
     * @method _positionChangeHandler
1582
     * @param {Object} e Event object
1583
     * @private
1584
     */
1585
    _positionChangeHandler: function(e)
1586
    {
1587
        this._updateGraphic(e.newVal);
1588
        this._updateHandler();
1589
    },
1590
 
1591
    /**
1592
     * Updates the the Graphic instance
1593
     *
1594
     * @method _updateGraphic
1595
     * @param {String} position Position of axis
1596
     * @private
1597
     */
1598
    _updateGraphic: function(position)
1599
    {
1600
        var graphic = this.get("graphic");
1601
        if(position === "none")
1602
        {
1603
            if(graphic)
1604
            {
1605
                graphic.destroy();
1606
            }
1607
        }
1608
        else
1609
        {
1610
            if(!graphic)
1611
            {
1612
                this._setCanvas();
1613
            }
1614
        }
1615
    },
1616
 
1617
    /**
1618
     * Handles changes to axis.
1619
     *
1620
     * @method _updateHandler
1621
     * @param {Object} e Event object
1622
     * @private
1623
     */
1624
    _updateHandler: function()
1625
    {
1626
        if(this.get("rendered"))
1627
        {
1628
            this._drawAxis();
1629
        }
1630
    },
1631
 
1632
    /**
1633
     * @method renderUI
1634
     * @private
1635
     */
1636
    renderUI: function()
1637
    {
1638
        this._updateGraphic(this.get("position"));
1639
    },
1640
 
1641
    /**
1642
     * @method syncUI
1643
     * @private
1644
     */
1645
    syncUI: function()
1646
    {
1647
        var layout = this._layout,
1648
            defaultMargins,
1649
            styles,
1650
            label,
1651
            title,
1652
            i;
1653
        if(layout)
1654
        {
1655
            defaultMargins = layout._getDefaultMargins();
1656
            styles = this.get("styles");
1657
            label = styles.label.margin;
1658
            title =styles.title.margin;
1659
            //need to defaultMargins method to the layout classes.
1660
            for(i in defaultMargins)
1661
            {
1662
                if(defaultMargins.hasOwnProperty(i))
1663
                {
1664
                    label[i] = label[i] === undefined ? defaultMargins[i] : label[i];
1665
                    title[i] = title[i] === undefined ? defaultMargins[i] : title[i];
1666
                }
1667
            }
1668
        }
1669
        this._drawAxis();
1670
    },
1671
 
1672
    /**
1673
     * Creates a graphic instance to be used for the axis line and ticks.
1674
     *
1675
     * @method _setCanvas
1676
     * @private
1677
     */
1678
    _setCanvas: function()
1679
    {
1680
        var cb = this.get("contentBox"),
1681
            bb = this.get("boundingBox"),
1682
            p = this.get("position"),
1683
            pn = this._parentNode,
1684
            w = this.get("width"),
1685
            h = this.get("height");
1686
        bb.setStyle("position", "absolute");
1687
        bb.setStyle("zIndex", 2);
1688
        w = w ? w + "px" : pn.getStyle("width");
1689
        h = h ? h + "px" : pn.getStyle("height");
1690
        if(p === "top" || p === "bottom")
1691
        {
1692
            cb.setStyle("width", w);
1693
        }
1694
        else
1695
        {
1696
            cb.setStyle("height", h);
1697
        }
1698
        cb.setStyle("position", "relative");
1699
        cb.setStyle("left", "0px");
1700
        cb.setStyle("top", "0px");
1701
        this.set("graphic", new Y.Graphic());
1702
        this.get("graphic").render(cb);
1703
    },
1704
 
1705
    /**
1706
     * Gets the default value for the `styles` attribute. Overrides
1707
     * base implementation.
1708
     *
1709
     * @method _getDefaultStyles
1710
     * @return Object
1711
     * @protected
1712
     */
1713
    _getDefaultStyles: function()
1714
    {
1715
        var axisstyles = {
1716
            majorTicks: {
1717
                display:"inside",
1718
                length:4,
1719
                color:"#dad8c9",
1720
                weight:1,
1721
                alpha:1
1722
            },
1723
            minorTicks: {
1724
                display:"none",
1725
                length:2,
1726
                color:"#dad8c9",
1727
                weight:1
1728
            },
1729
            line: {
1730
                weight:1,
1731
                color:"#dad8c9",
1732
                alpha:1
1733
            },
1734
            majorUnit: {
1735
                determinant:"count",
1736
                count:11,
1737
                distance:75
1738
            },
1739
            top: "0px",
1740
            left: "0px",
1741
            width: "100px",
1742
            height: "100px",
1743
            label: {
1744
                color:"#808080",
1745
                alpha: 1,
1746
                fontSize:"85%",
1747
                rotation: 0,
1748
                offset: 0.5,
1749
                margin: {
1750
                    top: undefined,
1751
                    right: undefined,
1752
                    bottom: undefined,
1753
                    left: undefined
1754
                }
1755
            },
1756
            title: {
1757
                color:"#808080",
1758
                alpha: 1,
1759
                fontSize:"85%",
1760
                rotation: undefined,
1761
                margin: {
1762
                    top: undefined,
1763
                    right: undefined,
1764
                    bottom: undefined,
1765
                    left: undefined
1766
                }
1767
            },
1768
            hideOverlappingLabelTicks: false
1769
        };
1770
 
1771
        return Y.merge(Y.Renderer.prototype._getDefaultStyles(), axisstyles);
1772
    },
1773
 
1774
    /**
1775
     * Updates the axis when the size changes.
1776
     *
1777
     * @method _handleSizeChange
1778
     * @param {Object} e Event object.
1779
     * @private
1780
     */
1781
    _handleSizeChange: function(e)
1782
    {
1783
        var attrName = e.attrName,
1784
            pos = this.get("position"),
1785
            vert = pos === "left" || pos === "right",
1786
            cb = this.get("contentBox"),
1787
            hor = pos === "bottom" || pos === "top";
1788
        cb.setStyle("width", this.get("width"));
1789
        cb.setStyle("height", this.get("height"));
1790
        if((hor && attrName === "width") || (vert && attrName === "height"))
1791
        {
1792
            this._drawAxis();
1793
        }
1794
    },
1795
 
1796
    /**
1797
     * Maps key values to classes containing layout algorithms
1798
     *
1799
     * @property _layoutClasses
1800
     * @type Object
1801
     * @private
1802
     */
1803
    _layoutClasses:
1804
    {
1805
        top : TopAxisLayout,
1806
        bottom: BottomAxisLayout,
1807
        left: LeftAxisLayout,
1808
        right : RightAxisLayout
1809
    },
1810
 
1811
    /**
1812
     * Draws a line segment between 2 points
1813
     *
1814
     * @method drawLine
1815
     * @param {Object} startPoint x and y coordinates for the start point of the line segment
1816
     * @param {Object} endPoint x and y coordinates for the for the end point of the line segment
1817
     * @param {Object} line styles (weight, color and alpha to be applied to the line segment)
1818
     * @private
1819
     */
1820
    drawLine: function(path, startPoint, endPoint)
1821
    {
1822
        path.moveTo(startPoint.x, startPoint.y);
1823
        path.lineTo(endPoint.x, endPoint.y);
1824
    },
1825
 
1826
    /**
1827
     * Generates the properties necessary for rotating and positioning a text field.
1828
     *
1829
     * @method _getTextRotationProps
1830
     * @param {Object} styles properties for the text field
1831
     * @return Object
1832
     * @private
1833
     */
1834
    _getTextRotationProps: function(styles)
1835
    {
1836
        if(styles.rotation === undefined)
1837
        {
1838
            switch(this.get("position"))
1839
            {
1840
                case "left" :
1841
                    styles.rotation = -90;
1842
                break;
1843
                case "right" :
1844
                    styles.rotation = 90;
1845
                break;
1846
                default :
1847
                    styles.rotation = 0;
1848
                break;
1849
            }
1850
        }
1851
        var rot =  Math.min(90, Math.max(-90, styles.rotation)),
1852
            absRot = Math.abs(rot),
1853
            radCon = Math.PI/180,
1854
            sinRadians = parseFloat(parseFloat(Math.sin(absRot * radCon)).toFixed(8)),
1855
            cosRadians = parseFloat(parseFloat(Math.cos(absRot * radCon)).toFixed(8));
1856
        return {
1857
            rot: rot,
1858
            absRot: absRot,
1859
            radCon: radCon,
1860
            sinRadians: sinRadians,
1861
            cosRadians: cosRadians,
1862
            textAlpha: styles.alpha
1863
        };
1864
    },
1865
 
1866
    /**
1867
     * Draws an axis.
1868
     *
1869
     * @method _drawAxis
1870
     * @private
1871
     */
1872
    _drawAxis: function ()
1873
    {
1874
        if(this._drawing)
1875
        {
1876
            this._callLater = true;
1877
            return;
1878
        }
1879
        this._drawing = true;
1880
        this._callLater = false;
1881
        if(this._layout)
1882
        {
1883
            var styles = this.get("styles"),
1884
                line = styles.line,
1885
                labelStyles = styles.label,
1886
                majorTickStyles = styles.majorTicks,
1887
                drawTicks = majorTickStyles.display !== "none",
1888
                len,
1889
                i = 0,
1890
                layout = this._layout,
1891
                layoutLength,
1892
                lineStart,
1893
                label,
1894
                labelWidth,
1895
                labelHeight,
1896
                labelFunction = this.get("labelFunction"),
1897
                labelFunctionScope = this.get("labelFunctionScope"),
1898
                labelFormat = this.get("labelFormat"),
1899
                graphic = this.get("graphic"),
1900
                path = this.get("path"),
1901
                tickPath,
1902
                explicitlySized,
1903
                position = this.get("position"),
1904
                labelData,
1905
                labelValues,
1906
                point,
1907
                points,
1908
                firstPoint,
1909
                lastPoint,
1910
                firstLabel,
1911
                lastLabel,
1912
                staticCoord,
1913
                dynamicCoord,
1914
                edgeOffset,
1915
                explicitLabels = this._labelValuesExplicitlySet ? this.get("labelValues") : null,
1916
                direction = (position === "left" || position === "right") ? "vertical" : "horizontal";
1917
            this._labelWidths = [];
1918
            this._labelHeights = [];
1919
            graphic.set("autoDraw", false);
1920
            path.clear();
1921
            path.set("stroke", {
1922
                weight: line.weight,
1923
                color: line.color,
1924
                opacity: line.alpha
1925
            });
1926
            this._labelRotationProps = this._getTextRotationProps(labelStyles);
1927
            this._labelRotationProps.transformOrigin = layout._getTransformOrigin(this._labelRotationProps.rot);
1928
            layout.setTickOffsets.apply(this);
1929
            layoutLength = this.getLength();
1930
 
1931
            len = this.getTotalMajorUnits();
1932
            edgeOffset = this.getEdgeOffset(len, layoutLength);
1933
            this.set("edgeOffset", edgeOffset);
1934
            lineStart = layout.getLineStart.apply(this);
1935
 
1936
            if(direction === "vertical")
1937
            {
1938
                staticCoord = "x";
1939
                dynamicCoord = "y";
1940
            }
1941
            else
1942
            {
1943
                staticCoord = "y";
1944
                dynamicCoord = "x";
1945
            }
1946
 
1947
            labelData = this._getLabelData(
1948
                lineStart[staticCoord],
1949
                staticCoord,
1950
                dynamicCoord,
1951
                this.get("minimum"),
1952
                this.get("maximum"),
1953
                edgeOffset,
1954
                layoutLength - edgeOffset - edgeOffset,
1955
                len,
1956
                explicitLabels
1957
            );
1958
 
1959
            points = labelData.points;
1960
            labelValues = labelData.values;
1961
            len = points.length;
1962
            if(!this._labelValuesExplicitlySet)
1963
            {
1964
                this.set("labelValues", labelValues, {src: "internal"});
1965
            }
1966
 
1967
            //Don't create the last label or tick.
1968
            if(this.get("hideFirstMajorUnit"))
1969
            {
1970
                firstPoint = points.shift();
1971
                firstLabel = labelValues.shift();
1972
                len = len - 1;
1973
            }
1974
 
1975
            //Don't create the last label or tick.
1976
            if(this.get("hideLastMajorUnit"))
1977
            {
1978
                lastPoint = points.pop();
1979
                lastLabel = labelValues.pop();
1980
                len = len - 1;
1981
            }
1982
 
1983
            if(len < 1)
1984
            {
1985
                this._clearLabelCache();
1986
            }
1987
            else
1988
            {
1989
                this.drawLine(path, lineStart, this.getLineEnd(lineStart));
1990
                if(drawTicks)
1991
                {
1992
                    tickPath = this.get("tickPath");
1993
                    tickPath.clear();
1994
                    tickPath.set("stroke", {
1995
                        weight: majorTickStyles.weight,
1996
                        color: majorTickStyles.color,
1997
                        opacity: majorTickStyles.alpha
1998
                    });
1999
                    for(i = 0; i < len; i = i + 1)
2000
                    {
2001
                        point = points[i];
2002
                        if(point)
2003
                        {
2004
                            layout.drawTick.apply(this, [tickPath, points[i], majorTickStyles]);
2005
                        }
2006
                    }
2007
                }
2008
                this._createLabelCache();
2009
                this._maxLabelSize = 0;
2010
                this._totalTitleSize = 0;
2011
                this._titleSize = 0;
2012
                this._setTitle();
2013
                explicitlySized = layout.getExplicitlySized.apply(this, [styles]);
2014
                for(i = 0; i < len; i = i + 1)
2015
                {
2016
                    point = points[i];
2017
                    if(point)
2018
                    {
2019
                        label = this.getLabel(labelStyles);
2020
                        this._labels.push(label);
2021
                        this.get("appendLabelFunction")(label, labelFunction.apply(labelFunctionScope, [labelValues[i], labelFormat]));
2022
                        labelWidth = Math.round(label.offsetWidth);
2023
                        labelHeight = Math.round(label.offsetHeight);
2024
                        if(!explicitlySized)
2025
                        {
2026
                            this._layout.updateMaxLabelSize.apply(this, [labelWidth, labelHeight]);
2027
                        }
2028
                        this._labelWidths.push(labelWidth);
2029
                        this._labelHeights.push(labelHeight);
2030
                    }
2031
                }
2032
                this._clearLabelCache();
2033
                if(this.get("overlapGraph"))
2034
                {
2035
                   layout.offsetNodeForTick.apply(this, [this.get("contentBox")]);
2036
                }
2037
                layout.setCalculatedSize.apply(this);
2038
                if(this._titleTextField)
2039
                {
2040
                    this._layout.positionTitle.apply(this, [this._titleTextField]);
2041
                }
2042
                len = this._labels.length;
2043
                for(i = 0; i < len; ++i)
2044
                {
2045
                    layout.positionLabel.apply(this, [this.get("labels")[i], points[i], styles, i]);
2046
                }
2047
                if(firstPoint)
2048
                {
2049
                    points.unshift(firstPoint);
2050
                }
2051
                if(lastPoint)
2052
                {
2053
                    points.push(lastPoint);
2054
                }
2055
                if(firstLabel)
2056
                {
2057
                    labelValues.unshift(firstLabel);
2058
                }
2059
                if(lastLabel)
2060
                {
2061
                    labelValues.push(lastLabel);
2062
                }
2063
                this._tickPoints = points;
2064
            }
2065
        }
2066
        this._drawing = false;
2067
        if(this._callLater)
2068
        {
2069
            this._drawAxis();
2070
        }
2071
        else
2072
        {
2073
            this._updatePathElement();
2074
            this.fire("axisRendered");
2075
        }
2076
    },
2077
 
2078
    /**
2079
     * Calculates and sets the total size of a title.
2080
     *
2081
     * @method _setTotalTitleSize
2082
     * @param {Object} styles Properties for the title field.
2083
     * @private
2084
     */
2085
    _setTotalTitleSize: function(styles)
2086
    {
2087
        var title = this._titleTextField,
2088
            w = title.offsetWidth,
2089
            h = title.offsetHeight,
2090
            rot = this._titleRotationProps.rot,
2091
            bounds,
2092
            size,
2093
            margin = styles.margin,
2094
            position = this.get("position"),
2095
            matrix = new Y.Matrix();
2096
        matrix.rotate(rot);
2097
        bounds = matrix.getContentRect(w, h);
2098
        if(position === "left" || position === "right")
2099
        {
2100
            size = bounds.right - bounds.left;
2101
            if(margin)
2102
            {
2103
                size += margin.left + margin.right;
2104
            }
2105
        }
2106
        else
2107
        {
2108
            size = bounds.bottom - bounds.top;
2109
            if(margin)
2110
            {
2111
                size += margin.top + margin.bottom;
2112
            }
2113
        }
2114
        this._titleBounds = bounds;
2115
        this._totalTitleSize = size;
2116
    },
2117
 
2118
    /**
2119
     *  Updates path.
2120
     *
2121
     *  @method _updatePathElement
2122
     *  @private
2123
     */
2124
    _updatePathElement: function()
2125
    {
2126
        var path = this._path,
2127
            tickPath = this._tickPath,
2128
            redrawGraphic = false,
2129
            graphic = this.get("graphic");
2130
        if(path)
2131
        {
2132
            redrawGraphic = true;
2133
            path.end();
2134
        }
2135
        if(tickPath)
2136
        {
2137
            redrawGraphic = true;
2138
            tickPath.end();
2139
        }
2140
        if(redrawGraphic)
2141
        {
2142
            graphic._redraw();
2143
        }
2144
    },
2145
 
2146
    /**
2147
     * Updates the content and style properties for a title field.
2148
     *
2149
     * @method _updateTitle
2150
     * @private
2151
     */
2152
    _setTitle: function()
2153
    {
2154
        var i,
2155
            styles,
2156
            customStyles,
2157
            title = this.get("title"),
2158
            titleTextField = this._titleTextField,
2159
            parentNode;
2160
        if(title !== null && title !== undefined)
2161
        {
2162
            customStyles = {
2163
                    rotation: "rotation",
2164
                    margin: "margin",
2165
                    alpha: "alpha"
2166
            };
2167
            styles = this.get("styles").title;
2168
            if(!titleTextField)
2169
            {
2170
                titleTextField = DOCUMENT.createElement('span');
2171
                titleTextField.style.display = "block";
2172
                titleTextField.style.whiteSpace = "nowrap";
2173
                titleTextField.setAttribute("class", "axisTitle");
2174
                this.get("contentBox").append(titleTextField);
2175
            }
2176
            else if(!DOCUMENT.createElementNS)
2177
            {
2178
                if(titleTextField.style.filter)
2179
                {
2180
                    titleTextField.style.filter = null;
2181
                }
2182
            }
2183
            titleTextField.style.position = "absolute";
2184
            for(i in styles)
2185
            {
2186
                if(styles.hasOwnProperty(i) && !customStyles.hasOwnProperty(i))
2187
                {
2188
                    titleTextField.style[i] = styles[i];
2189
                }
2190
            }
2191
            this.get("appendTitleFunction")(titleTextField, title);
2192
            this._titleTextField = titleTextField;
2193
            this._titleRotationProps = this._getTextRotationProps(styles);
2194
            this._setTotalTitleSize(styles);
2195
        }
2196
        else if(titleTextField)
2197
        {
2198
            parentNode = titleTextField.parentNode;
2199
            if(parentNode)
2200
            {
2201
                parentNode.removeChild(titleTextField);
2202
            }
2203
            this._titleTextField = null;
2204
            this._totalTitleSize = 0;
2205
        }
2206
    },
2207
 
2208
    /**
2209
     * Creates or updates an axis label.
2210
     *
2211
     * @method getLabel
2212
     * @param {Object} styles styles applied to label
2213
     * @return HTMLElement
2214
     * @private
2215
     */
2216
    getLabel: function(styles)
2217
    {
2218
        var i,
2219
            label,
2220
            labelCache = this._labelCache,
2221
            customStyles = {
2222
                rotation: "rotation",
2223
                margin: "margin",
2224
                alpha: "alpha"
2225
            };
2226
        if(labelCache && labelCache.length > 0)
2227
        {
2228
            label = labelCache.shift();
2229
        }
2230
        else
2231
        {
2232
            label = DOCUMENT.createElement("span");
2233
            label.className = Y.Lang.trim([label.className, "axisLabel"].join(' '));
2234
            this.get("contentBox").append(label);
2235
        }
2236
        if(!DOCUMENT.createElementNS)
2237
        {
2238
            if(label.style.filter)
2239
            {
2240
                label.style.filter = null;
2241
            }
2242
        }
2243
        label.style.display = "block";
2244
        label.style.whiteSpace = "nowrap";
2245
        label.style.position = "absolute";
2246
        for(i in styles)
2247
        {
2248
            if(styles.hasOwnProperty(i) && !customStyles.hasOwnProperty(i))
2249
            {
2250
                label.style[i] = styles[i];
2251
            }
2252
        }
2253
        return label;
2254
    },
2255
 
2256
    /**
2257
     * Creates a cache of labels that can be re-used when the axis redraws.
2258
     *
2259
     * @method _createLabelCache
2260
     * @private
2261
     */
2262
    _createLabelCache: function()
2263
    {
2264
        if(this._labels)
2265
        {
2266
            while(this._labels.length > 0)
2267
            {
2268
                this._labelCache.push(this._labels.shift());
2269
            }
2270
        }
2271
        else
2272
        {
2273
            this._clearLabelCache();
2274
        }
2275
        this._labels = [];
2276
    },
2277
 
2278
    /**
2279
     * Removes axis labels from the dom and clears the label cache.
2280
     *
2281
     * @method _clearLabelCache
2282
     * @private
2283
     */
2284
    _clearLabelCache: function()
2285
    {
2286
        if(this._labelCache)
2287
        {
2288
            var len = this._labelCache.length,
2289
                i = 0,
2290
                label;
2291
            for(; i < len; ++i)
2292
            {
2293
                label = this._labelCache[i];
2294
                this._removeChildren(label);
2295
                Y.Event.purgeElement(label, true);
2296
                label.parentNode.removeChild(label);
2297
            }
2298
        }
2299
        this._labelCache = [];
2300
    },
2301
 
2302
    /**
2303
     * Gets the end point of an axis.
2304
     *
2305
     * @method getLineEnd
2306
     * @return Object
2307
     * @private
2308
     */
2309
    getLineEnd: function(pt)
2310
    {
2311
        var w = this.get("width"),
2312
            h = this.get("height"),
2313
            pos = this.get("position");
2314
        if(pos === "top" || pos === "bottom")
2315
        {
2316
            return {x:w, y:pt.y};
2317
        }
2318
        else
2319
        {
2320
            return {x:pt.x, y:h};
2321
        }
2322
    },
2323
 
2324
    /**
2325
     * Calcuates the width or height of an axis depending on its direction.
2326
     *
2327
     * @method getLength
2328
     * @return Number
2329
     * @private
2330
     */
2331
    getLength: function()
2332
    {
2333
        var l,
2334
            style = this.get("styles"),
2335
            padding = style.padding,
2336
            w = this.get("width"),
2337
            h = this.get("height"),
2338
            pos = this.get("position");
2339
        if(pos === "top" || pos === "bottom")
2340
        {
2341
            l = w - (padding.left + padding.right);
2342
        }
2343
        else
2344
        {
2345
            l = h - (padding.top + padding.bottom);
2346
        }
2347
        return l;
2348
    },
2349
 
2350
    /**
2351
     * Gets the position of the first point on an axis.
2352
     *
2353
     * @method getFirstPoint
2354
     * @param {Object} pt Object containing x and y coordinates.
2355
     * @return Object
2356
     * @private
2357
     */
2358
    getFirstPoint:function(pt)
2359
    {
2360
        var style = this.get("styles"),
2361
            pos = this.get("position"),
2362
            padding = style.padding,
2363
            np = {x:pt.x, y:pt.y};
2364
        if(pos === "top" || pos === "bottom")
2365
        {
2366
            np.x += padding.left + this.get("edgeOffset");
2367
        }
2368
        else
2369
        {
2370
            np.y += this.get("height") - (padding.top + this.get("edgeOffset"));
2371
        }
2372
        return np;
2373
    },
2374
 
2375
    /**
2376
     * Rotates and positions a text field.
2377
     *
2378
     * @method _rotate
2379
     * @param {HTMLElement} label text field to rotate and position
2380
     * @param {Object} props properties to be applied to the text field.
2381
     * @private
2382
     */
2383
    _rotate: function(label, props)
2384
    {
2385
        var rot = props.rot,
2386
            x = props.x,
2387
            y = props.y,
2388
            filterString,
2389
            textAlpha,
2390
            matrix = new Y.Matrix(),
2391
            transformOrigin = props.transformOrigin || [0, 0],
2392
            offsetRect;
2393
        if(DOCUMENT.createElementNS)
2394
        {
2395
            matrix.translate(x, y);
2396
            matrix.rotate(rot);
2397
            Y_DOM.setStyle(label, "transformOrigin", (transformOrigin[0] * 100) + "% " + (transformOrigin[1] * 100) + "%");
2398
            Y_DOM.setStyle(label, "transform", matrix.toCSSText());
2399
        }
2400
        else
2401
        {
2402
            textAlpha = props.textAlpha;
2403
            if(Y_Lang.isNumber(textAlpha) && textAlpha < 1 && textAlpha > -1 && !isNaN(textAlpha))
2404
            {
2405
                filterString = "progid:DXImageTransform.Microsoft.Alpha(Opacity=" + Math.round(textAlpha * 100) + ")";
2406
            }
2407
            if(rot !== 0)
2408
            {
2409
                //ms filters kind of, sort of uses a transformOrigin of 0, 0.
2410
                //we'll translate the difference to create a true 0, 0 origin.
2411
                matrix.rotate(rot);
2412
                offsetRect = matrix.getContentRect(props.labelWidth, props.labelHeight);
2413
                matrix.init();
2414
                matrix.translate(offsetRect.left, offsetRect.top);
2415
                matrix.translate(x, y);
2416
                this._simulateRotateWithTransformOrigin(matrix, rot, transformOrigin, props.labelWidth, props.labelHeight);
2417
                if(filterString)
2418
                {
2419
                    filterString += " ";
2420
                }
2421
                else
2422
                {
2423
                    filterString = "";
2424
                }
2425
                filterString += matrix.toFilterText();
2426
                label.style.left = matrix.dx + "px";
2427
                label.style.top = matrix.dy + "px";
2428
            }
2429
            else
2430
            {
2431
                label.style.left = x + "px";
2432
                label.style.top = y + "px";
2433
            }
2434
            if(filterString)
2435
            {
2436
                label.style.filter = filterString;
2437
            }
2438
        }
2439
    },
2440
 
2441
    /**
2442
     * Simulates a rotation with a specified transformOrigin.
2443
     *
2444
     * @method _simulateTransformOrigin
2445
     * @param {Matrix} matrix Reference to a `Matrix` instance.
2446
     * @param {Number} rot The rotation (in degrees) that will be performed on a matrix.
2447
     * @param {Array} transformOrigin An array represeniting the origin in which to perform the transform. The first
2448
     * index represents the x origin and the second index represents the y origin.
2449
     * @param {Number} w The width of the object that will be transformed.
2450
     * @param {Number} h The height of the object that will be transformed.
2451
     * @private
2452
     */
2453
    _simulateRotateWithTransformOrigin: function(matrix, rot, transformOrigin, w, h)
2454
    {
2455
        var transformX = transformOrigin[0] * w,
2456
            transformY = transformOrigin[1] * h;
2457
        transformX = !isNaN(transformX) ? transformX : 0;
2458
        transformY = !isNaN(transformY) ? transformY : 0;
2459
        matrix.translate(transformX, transformY);
2460
        matrix.rotate(rot);
2461
        matrix.translate(-transformX, -transformY);
2462
    },
2463
 
2464
    /**
2465
     * Returns the coordinates (top, right, bottom, left) for the bounding box of the last label.
2466
     *
2467
     * @method getMaxLabelBounds
2468
     * @return Object
2469
     */
2470
    getMaxLabelBounds: function()
2471
    {
2472
        return this._getLabelBounds(this.getMaximumValue());
2473
    },
2474
 
2475
    /**
2476
     * Returns the coordinates (top, right, bottom, left) for the bounding box of the first label.
2477
     *
2478
     * @method getMinLabelBounds
2479
     * @return Object
2480
     */
2481
    getMinLabelBounds: function()
2482
    {
2483
        return this._getLabelBounds(this.getMinimumValue());
2484
    },
2485
 
2486
    /**
2487
     * Returns the coordinates (top, right, bottom, left) for the bounding box of a label.
2488
     *
2489
     * @method _getLabelBounds
2490
     * @param {String} Value of the label
2491
     * @return Object
2492
     * @private
2493
     */
2494
    _getLabelBounds: function(val)
2495
    {
2496
        var layout = this._layout,
2497
            labelStyles = this.get("styles").label,
2498
            matrix = new Y.Matrix(),
2499
            label,
2500
            props = this._getTextRotationProps(labelStyles);
2501
            props.transformOrigin = layout._getTransformOrigin(props.rot);
2502
        label = this.getLabel(labelStyles);
2503
        this.get("appendLabelFunction")(label, this.get("labelFunction").apply(this, [val, this.get("labelFormat")]));
2504
        props.labelWidth = label.offsetWidth;
2505
        props.labelHeight = label.offsetHeight;
2506
        this._removeChildren(label);
2507
        Y.Event.purgeElement(label, true);
2508
        label.parentNode.removeChild(label);
2509
        props.x = 0;
2510
        props.y = 0;
2511
        layout._setRotationCoords(props);
2512
        matrix.translate(props.x, props.y);
2513
        this._simulateRotateWithTransformOrigin(matrix, props.rot, props.transformOrigin, props.labelWidth, props.labelHeight);
2514
        return matrix.getContentRect(props.labelWidth, props.labelHeight);
2515
    },
2516
 
2517
    /**
2518
     * Removes all DOM elements from an HTML element. Used to clear out labels during detruction
2519
     * phase.
2520
     *
2521
     * @method _removeChildren
2522
     * @private
2523
     */
2524
    _removeChildren: function(node)
2525
    {
2526
        if(node.hasChildNodes())
2527
        {
2528
            var child;
2529
            while(node.firstChild)
2530
            {
2531
                child = node.firstChild;
2532
                this._removeChildren(child);
2533
                node.removeChild(child);
2534
            }
2535
        }
2536
    },
2537
 
2538
    /**
2539
     * Destructor implementation Axis class. Removes all labels and the Graphic instance from the widget.
2540
     *
2541
     * @method destructor
2542
     * @protected
2543
     */
2544
    destructor: function()
2545
    {
2546
        var cb = this.get("contentBox").getDOMNode(),
2547
            labels = this.get("labels"),
2548
            graphic = this.get("graphic"),
2549
            label,
2550
            len = labels ? labels.length : 0;
2551
        if(len > 0)
2552
        {
2553
            while(labels.length > 0)
2554
            {
2555
                label = labels.shift();
2556
                this._removeChildren(label);
2557
                cb.removeChild(label);
2558
                label = null;
2559
            }
2560
        }
2561
        if(graphic)
2562
        {
2563
            graphic.destroy();
2564
        }
2565
    },
2566
 
2567
    /**
2568
     * Length in pixels of largest text bounding box. Used to calculate the height of the axis.
2569
     *
2570
     * @property maxLabelSize
2571
     * @type Number
2572
     * @protected
2573
     */
2574
    _maxLabelSize: 0,
2575
 
2576
    /**
2577
     * Updates the content of text field. This method writes a value into a text field using
2578
     * `appendChild`. If the value is a `String`, it is converted to a `TextNode` first.
2579
     *
2580
     * @method _setText
2581
     * @param label {HTMLElement} label to be updated
2582
     * @param val {String} value with which to update the label
2583
     * @private
2584
     */
2585
    _setText: function(textField, val)
2586
    {
2587
        textField.innerHTML = "";
2588
        if(Y_Lang.isNumber(val))
2589
        {
2590
            val = val + "";
2591
        }
2592
        else if(!val)
2593
        {
2594
            val = "";
2595
        }
2596
        if(IS_STRING(val))
2597
        {
2598
            val = DOCUMENT.createTextNode(val);
2599
        }
2600
        textField.appendChild(val);
2601
    },
2602
 
2603
    /**
2604
     * Returns the total number of majorUnits that will appear on an axis.
2605
     *
2606
     * @method getTotalMajorUnits
2607
     * @return Number
2608
     */
2609
    getTotalMajorUnits: function()
2610
    {
2611
        var units,
2612
            majorUnit = this.get("styles").majorUnit,
2613
            len;
2614
        if(majorUnit.determinant === "count")
2615
        {
2616
            units = majorUnit.count;
2617
        }
2618
        else if(majorUnit.determinant === "distance")
2619
        {
2620
            len = this.getLength();
2621
            units = (len/majorUnit.distance) + 1;
2622
        }
2623
        return units;
2624
    },
2625
 
2626
    /**
2627
     * Returns the distance between major units on an axis.
2628
     *
2629
     * @method getMajorUnitDistance
2630
     * @param {Number} len Number of ticks
2631
     * @param {Number} uiLen Size of the axis.
2632
     * @param {Object} majorUnit Hash of properties used to determine the majorUnit
2633
     * @return Number
2634
     */
2635
    getMajorUnitDistance: function(len, uiLen, majorUnit)
2636
    {
2637
        var dist;
2638
        if(majorUnit.determinant === "count")
2639
        {
2640
            if(!this.get("calculateEdgeOffset"))
2641
            {
2642
                len = len - 1;
2643
            }
2644
            dist = uiLen/len;
2645
        }
2646
        else if(majorUnit.determinant === "distance")
2647
        {
2648
            dist = majorUnit.distance;
2649
        }
2650
        return dist;
2651
    },
2652
 
2653
    /**
2654
     * Checks to see if data extends beyond the range of the axis. If so,
2655
     * that data will need to be hidden. This method is internal, temporary and subject
2656
     * to removal in the future.
2657
     *
2658
     * @method _hasDataOverflow
2659
     * @protected
2660
     * @return Boolean
2661
     */
2662
    _hasDataOverflow: function()
2663
    {
2664
        if(this.get("setMin") || this.get("setMax"))
2665
        {
2666
            return true;
2667
        }
2668
        return false;
2669
    },
2670
 
2671
    /**
2672
     * Returns a string corresponding to the first label on an
2673
     * axis.
2674
     *
2675
     * @method getMinimumValue
2676
     * @return String
2677
     */
2678
    getMinimumValue: function()
2679
    {
2680
        return this.get("minimum");
2681
    },
2682
 
2683
    /**
2684
     * Returns a string corresponding to the last label on an
2685
     * axis.
2686
     *
2687
     * @method getMaximumValue
2688
     * @return String
2689
     */
2690
    getMaximumValue: function()
2691
    {
2692
        return this.get("maximum");
2693
    }
2694
}, {
2695
    ATTRS:
2696
    {
2697
        /**
2698
         * When set, defines the width of a vertical axis instance. By default, vertical axes automatically size based
2699
         * on their contents. When the width attribute is set, the axis will not calculate its width. When the width
2700
         * attribute is explicitly set, axis labels will postion themselves off of the the inner edge of the axis and the
2701
         * title, if present, will position itself off of the outer edge. If a specified width is less than the sum of
2702
         * the axis' contents, excess content will overflow.
2703
         *
2704
         * @attribute width
2705
         * @type Number
2706
         */
2707
        width: {
2708
            lazyAdd: false,
2709
 
2710
            getter: function()
2711
            {
2712
                if(this._explicitWidth)
2713
                {
2714
                    return this._explicitWidth;
2715
                }
2716
                return this._calculatedWidth;
2717
            },
2718
 
2719
            setter: function(val)
2720
            {
2721
                this._explicitWidth = val;
2722
                return val;
2723
            }
2724
        },
2725
 
2726
        /**
2727
         * When set, defines the height of a horizontal axis instance. By default, horizontal axes automatically size based
2728
         * on their contents. When the height attribute is set, the axis will not calculate its height. When the height
2729
         * attribute is explicitly set, axis labels will postion themselves off of the the inner edge of the axis and the
2730
         * title, if present, will position itself off of the outer edge. If a specified height is less than the sum of
2731
         * the axis' contents, excess content will overflow.
2732
         *
2733
         * @attribute height
2734
         * @type Number
2735
         */
2736
        height: {
2737
            lazyAdd: false,
2738
 
2739
            getter: function()
2740
            {
2741
                if(this._explicitHeight)
2742
                {
2743
                    return this._explicitHeight;
2744
                }
2745
                return this._calculatedHeight;
2746
            },
2747
 
2748
            setter: function(val)
2749
            {
2750
                this._explicitHeight = val;
2751
                return val;
2752
            }
2753
        },
2754
 
2755
        /**
2756
         * Calculated value of an axis' width. By default, the value is used internally for vertical axes. If the `width`
2757
         * attribute is explicitly set, this value will be ignored.
2758
         *
2759
         * @attribute calculatedWidth
2760
         * @type Number
2761
         * @private
2762
         */
2763
        calculatedWidth: {
2764
            getter: function()
2765
            {
2766
                return this._calculatedWidth;
2767
            },
2768
 
2769
            setter: function(val)
2770
            {
2771
                this._calculatedWidth = val;
2772
                return val;
2773
            }
2774
        },
2775
 
2776
        /**
2777
         * Calculated value of an axis' height. By default, the value is used internally for horizontal axes. If the `height`
2778
         * attribute is explicitly set, this value will be ignored.
2779
         *
2780
         * @attribute calculatedHeight
2781
         * @type Number
2782
         * @private
2783
         */
2784
        calculatedHeight: {
2785
            getter: function()
2786
            {
2787
                return this._calculatedHeight;
2788
            },
2789
 
2790
            setter: function(val)
2791
            {
2792
                this._calculatedHeight = val;
2793
                return val;
2794
            }
2795
        },
2796
 
2797
        /**
2798
         * Difference between the first/last tick and edge of axis.
2799
         *
2800
         * @attribute edgeOffset
2801
         * @type Number
2802
         * @protected
2803
         */
2804
        edgeOffset:
2805
        {
2806
            value: 0
2807
        },
2808
 
2809
        /**
2810
         * The graphic in which the axis line and ticks will be rendered.
2811
         *
2812
         * @attribute graphic
2813
         * @type Graphic
2814
         */
2815
        graphic: {},
2816
 
2817
        /**
2818
         *  @attribute path
2819
         *  @type Shape
2820
         *  @readOnly
2821
         *  @private
2822
         */
2823
        path: {
2824
            readOnly: true,
2825
 
2826
            getter: function()
2827
            {
2828
                if(!this._path)
2829
                {
2830
                    var graphic = this.get("graphic");
2831
                    if(graphic)
2832
                    {
2833
                        this._path = graphic.addShape({type:"path"});
2834
                    }
2835
                }
2836
                return this._path;
2837
            }
2838
        },
2839
 
2840
        /**
2841
         *  @attribute tickPath
2842
         *  @type Shape
2843
         *  @readOnly
2844
         *  @private
2845
         */
2846
        tickPath: {
2847
            readOnly: true,
2848
 
2849
            getter: function()
2850
            {
2851
                if(!this._tickPath)
2852
                {
2853
                    var graphic = this.get("graphic");
2854
                    if(graphic)
2855
                    {
2856
                        this._tickPath = graphic.addShape({type:"path"});
2857
                    }
2858
                }
2859
                return this._tickPath;
2860
            }
2861
        },
2862
 
2863
        /**
2864
         * Contains the contents of the axis.
2865
         *
2866
         * @attribute node
2867
         * @type HTMLElement
2868
         */
2869
        node: {},
2870
 
2871
        /**
2872
         * Direction of the axis.
2873
         *
2874
         * @attribute position
2875
         * @type String
2876
         */
2877
        position: {
2878
            lazyAdd: false,
2879
 
2880
            setter: function(val)
2881
            {
2882
                var LayoutClass = this._layoutClasses[val];
2883
                if(val && val !== "none")
2884
                {
2885
                    this._layout = new LayoutClass();
2886
                }
2887
                return val;
2888
            }
2889
        },
2890
 
2891
        /**
2892
         * Distance determined by the tick styles used to calculate the distance between the axis
2893
         * line in relation to the top of the axis.
2894
         *
2895
         * @attribute topTickOffset
2896
         * @type Number
2897
         */
2898
        topTickOffset: {
2899
            value: 0
2900
        },
2901
 
2902
        /**
2903
         * Distance determined by the tick styles used to calculate the distance between the axis
2904
         * line in relation to the bottom of the axis.
2905
         *
2906
         * @attribute bottomTickOffset
2907
         * @type Number
2908
         */
2909
        bottomTickOffset: {
2910
            value: 0
2911
        },
2912
 
2913
        /**
2914
         * Distance determined by the tick styles used to calculate the distance between the axis
2915
         * line in relation to the left of the axis.
2916
         *
2917
         * @attribute leftTickOffset
2918
         * @type Number
2919
         */
2920
        leftTickOffset: {
2921
            value: 0
2922
        },
2923
 
2924
        /**
2925
         * Distance determined by the tick styles used to calculate the distance between the axis
2926
         * line in relation to the right side of the axis.
2927
         *
2928
         * @attribute rightTickOffset
2929
         * @type Number
2930
         */
2931
        rightTickOffset: {
2932
            value: 0
2933
        },
2934
 
2935
        /**
2936
         * Collection of labels used to render the axis.
2937
         *
2938
         * @attribute labels
2939
         * @type Array
2940
         */
2941
        labels: {
2942
            readOnly: true,
2943
            getter: function()
2944
            {
2945
                return this._labels;
2946
            }
2947
        },
2948
 
2949
        /**
2950
         * Collection of points used for placement of labels and ticks along the axis.
2951
         *
2952
         * @attribute tickPoints
2953
         * @type Array
2954
         */
2955
        tickPoints: {
2956
            readOnly: true,
2957
 
2958
            getter: function()
2959
            {
2960
                if(this.get("position") === "none")
2961
                {
2962
                    return this.get("styles").majorUnit.count;
2963
                }
2964
                return this._tickPoints;
2965
            }
2966
        },
2967
 
2968
        /**
2969
         * Indicates whether the axis overlaps the graph. If an axis is the inner most axis on a given
2970
         * position and the tick position is inside or cross, the axis will need to overlap the graph.
2971
         *
2972
         * @attribute overlapGraph
2973
         * @type Boolean
2974
         */
2975
        overlapGraph: {
2976
            value:true,
2977
 
2978
            validator: function(val)
2979
            {
2980
                return Y_Lang.isBoolean(val);
2981
            }
2982
        },
2983
 
2984
        /**
2985
         * Length in pixels of largest text bounding box. Used to calculate the height of the axis.
2986
         *
2987
         * @attribute maxLabelSize
2988
         * @type Number
2989
         * @protected
2990
         */
2991
        maxLabelSize: {
2992
            getter: function()
2993
            {
2994
                return this._maxLabelSize;
2995
            },
2996
 
2997
            setter: function(val)
2998
            {
2999
                this._maxLabelSize = val;
3000
                return val;
3001
            }
3002
        },
3003
 
3004
        /**
3005
         *  Title for the axis. When specified, the title will display. The position of the title is determined by the axis position.
3006
         *  <dl>
3007
         *      <dt>top</dt><dd>Appears above the axis and it labels. The default rotation is 0.</dd>
3008
         *      <dt>right</dt><dd>Appears to the right of the axis and its labels. The default rotation is 90.</dd>
3009
         *      <dt>bottom</dt><dd>Appears below the axis and its labels. The default rotation is 0.</dd>
3010
         *      <dt>left</dt><dd>Appears to the left of the axis and its labels. The default rotation is -90.</dd>
3011
         *  </dl>
3012
         *
3013
         *  @attribute title
3014
         *  @type String
3015
         */
3016
        title: {
3017
            value: null
3018
        },
3019
 
3020
        /**
3021
         * Function used to append an axis value to an axis label. This function has the following signature:
3022
         *  <dl>
3023
         *      <dt>textField</dt><dd>The axis label to be appended. (`HTMLElement`)</dd>
3024
         *      <dt>val</dt><dd>The value to attach to the text field. This method will accept an `HTMLELement`
3025
         *      or a `String`. This method does not use (`HTMLElement` | `String`)</dd>
3026
         *  </dl>
3027
         * The default method appends a value to the `HTMLElement` using the `appendChild` method. If the given
3028
         * value is a `String`, the method will convert the the value to a `textNode` before appending to the
3029
         * `HTMLElement`. This method will not convert an `HTMLString` to an `HTMLElement`.
3030
         *
3031
         * @attribute appendLabelFunction
3032
         * @type Function
3033
         */
3034
        appendLabelFunction: {
3035
            valueFn: function()
3036
            {
3037
                return this._setText;
3038
            }
3039
        },
3040
 
3041
        /**
3042
         * Function used to append a title value to the title object. This function has the following signature:
3043
         *  <dl>
3044
         *      <dt>textField</dt><dd>The title text field to be appended. (`HTMLElement`)</dd>
3045
         *      <dt>val</dt><dd>The value to attach to the text field. This method will accept an `HTMLELement`
3046
         *      or a `String`. This method does not use (`HTMLElement` | `String`)</dd>
3047
         *  </dl>
3048
         * The default method appends a value to the `HTMLElement` using the `appendChild` method. If the given
3049
         * value is a `String`, the method will convert the the value to a `textNode` before appending to the
3050
         * `HTMLElement` element. This method will not convert an `HTMLString` to an `HTMLElement`.
3051
         *
3052
         * @attribute appendTitleFunction
3053
         * @type Function
3054
         */
3055
        appendTitleFunction: {
3056
            valueFn: function()
3057
            {
3058
                return this._setText;
3059
            }
3060
        },
3061
 
3062
        /**
3063
         * An array containing the unformatted values of the axis labels. By default, TimeAxis, NumericAxis and
3064
         * StackedAxis labelValues are determined by the majorUnit style. By default, CategoryAxis labels are
3065
         * determined by the values of the dataProvider.
3066
         * <p>When the labelValues attribute is explicitly set, the labelValues are dictated by the set value and
3067
         * the position of ticks and labels are determined by where those values would fall on the axis. </p>
3068
         *
3069
         * @attribute labelValues
3070
         * @type Array
3071
         */
3072
        labelValues: {
3073
            lazyAdd: false,
3074
 
3075
            setter: function(val)
3076
            {
3077
                var opts = arguments[2];
3078
                if(!val || (opts && opts.src && opts.src === "internal"))
3079
                {
3080
                    this._labelValuesExplicitlySet = false;
3081
                }
3082
                else
3083
                {
3084
                    this._labelValuesExplicitlySet = true;
3085
                }
3086
                return val;
3087
            }
3088
        },
3089
 
3090
        /**
3091
         * Suppresses the creation of the the first visible label and tick.
3092
         *
3093
         * @attribute hideFirstMajorUnit
3094
         * @type Boolean
3095
         */
3096
        hideFirstMajorUnit: {
3097
            value: false
3098
        },
3099
 
3100
        /**
3101
         * Suppresses the creation of the the last visible label and tick.
3102
         *
3103
         * @attribute hideLastMajorUnit
3104
         * @type Boolean
3105
         */
3106
        hideLastMajorUnit: {
3107
            value: false
3108
        }
3109
 
3110
        /**
3111
         * Style properties used for drawing an axis. This attribute is inherited from `Renderer`. Below are the default values:
3112
         *  <dl>
3113
         *      <dt>majorTicks</dt><dd>Properties used for drawing ticks.
3114
         *          <dl>
3115
         *              <dt>display</dt><dd>Position of the tick. Possible values are `inside`, `outside`, `cross` and `none`.
3116
         *              The default value is `inside`.</dd>
3117
         *              <dt>length</dt><dd>The length (in pixels) of the tick. The default value is 4.</dd>
3118
         *              <dt>color</dt><dd>The color of the tick. The default value is `#dad8c9`</dd>
3119
         *              <dt>weight</dt><dd>Number indicating the width of the tick. The default value is 1.</dd>
3120
         *              <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the tick. The default value is 1.</dd>
3121
         *          </dl>
3122
         *      </dd>
3123
         *      <dt>line</dt><dd>Properties used for drawing the axis line.
3124
         *          <dl>
3125
         *              <dt>weight</dt><dd>Number indicating the width of the axis line. The default value is 1.</dd>
3126
         *              <dt>color</dt><dd>The color of the axis line. The default value is `#dad8c9`.</dd>
3127
         *              <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the tick. The default value is 1.</dd>
3128
         *          </dl>
3129
         *      </dd>
3130
         *      <dt>majorUnit</dt><dd>Properties used to calculate the `majorUnit` for the axis.
3131
         *          <dl>
3132
         *              <dt>determinant</dt><dd>The algorithm used for calculating distance between ticks. The possible options are
3133
         *              `count` and `distance`. If the `determinant` is `count`, the axis ticks will spaced so that a specified number
3134
         *              of ticks appear on the axis. If the `determinant` is `distance`, the axis ticks will spaced out according to
3135
         *              the specified distance. The default value is `count`.</dd>
3136
         *              <dt>count</dt><dd>Number of ticks to appear on the axis when the `determinant` is `count`. The default value is 11.</dd>
3137
         *              <dt>distance</dt><dd>The distance (in pixels) between ticks when the `determinant` is `distance`. The default
3138
         *              value is 75.</dd>
3139
         *          </dl>
3140
         *      </dd>
3141
         *      <dt>label</dt><dd>Properties and styles applied to the axis labels.
3142
         *          <dl>
3143
         *              <dt>color</dt><dd>The color of the labels. The default value is `#808080`.</dd>
3144
         *              <dt>alpha</dt><dd>Number between 0 and 1 indicating the opacity of the labels. The default value is 1.</dd>
3145
         *              <dt>fontSize</dt><dd>The font-size of the labels. The default value is 85%</dd>
3146
         *              <dt>rotation</dt><dd>The rotation, in degrees (between -90 and 90) of the labels. The default value is 0.</dd>
3147
         *              <dt>offset</td><dd>A number between 0 and 1 indicating the relationship of the label to a tick. For a horizontal axis
3148
         *              label, a value of 0 will position the label's left side even to the the tick. A position of 1 would position the
3149
         *              right side of the label with the tick. A position of 0.5 would center the label horizontally with the tick. For a
3150
         *              vertical axis, a value of 0 would position the top of the label with the tick, a value of 1 would position the bottom
3151
         *              of the label with the tick and a value 0 would center the label vertically with the tick. The default value is 0.5.</dd>
3152
         *              <dt>margin</dt><dd>The distance between the label and the axis/tick. Depending on the position of the `Axis`,
3153
         *              only one of the properties used.
3154
         *                  <dl>
3155
         *                      <dt>top</dt><dd>Pixel value used for an axis with a `position` of `bottom`. The default value is 4.</dd>
3156
         *                      <dt>right</dt><dd>Pixel value used for an axis with a `position` of `left`. The default value is 4.</dd>
3157
         *                      <dt>bottom</dt><dd>Pixel value used for an axis with a `position` of `top`. The default value is 4.</dd>
3158
         *                      <dt>left</dt><dd>Pixel value used for an axis with a `position` of `right`. The default value is 4.</dd>
3159
         *                  </dl>
3160
         *              </dd>
3161
         *          </dl>
3162
         *      </dd>
3163
         *  </dl>
3164
         *
3165
         * @attribute styles
3166
         * @type Object
3167
         */
3168
    }
3169
});
3170
Y.AxisType = Y.Base.create("baseAxis", Y.Axis, [], {});
3171
 
3172
 
3173
}, '3.18.1', {"requires": ["dom", "widget", "widget-position", "widget-stack", "graphics", "axis-base"]});