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

« back to all changes in this revision

Viewing changes to lib/yuilib/3.13.0/axis/axis-debug.js

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

Show diffs side-by-side

added added

removed removed

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