# Yahoo! UI Library

### charts 3.3.0

Yahoo! UI Library > charts > Axis.js (source view)
Search:
Filters Show Private Show Protected Show Deprecated

    /**
     * The Axis class. Generates axes for a chart.
     *
     * @class Axis
     * @extends Renderer
     * @constructor
     */
    Y.Axis = Y.Base.create("axis", Y.Widget, [Y.Renderer], {
        /**
         * @private
         */
        _dataChangeHandler: function(e)
        {
            if(this.get("rendered"))
            {
                this._drawAxis();
            }
        },

        /**
         * @private
         */
        _updateHandler: function(e)
        {
            if(this.get("rendered"))
            {
                this._drawAxis();
            }
        },

        /**
         * @private
         */
        _positionChangeHandler: function(e)
        {
            var position = this.get("position");
            if(position == "none")
            {
                return;
            }
            this._layout =this.getLayout(this.get("position"));
            if(this.get("rendered"))
            {
                this._drawAxis();
            }
        },

        /**
         * @private
         */
        renderUI: function()
        {
            var pos = this.get("position");
            if(pos && pos != "none")
            {
                this._layout =this.getLayout(pos);
                this._setCanvas();
            }
        },

        /**
         * @private
         */
        syncUI: function()
        {
            this._drawAxis();
        },

        /**
         * @private
         */
        _setCanvas: function()
        {
            var cb = this.get("contentBox"),
                bb = this.get("boundingBox"),
                p = this.get("position"),
                pn = this._parentNode,
                w = this.get("width"),
                h = this.get("height");
            bb.setStyle("position", "absolute");
            w = w ? w + "px" : pn.getStyle("width");
            h = h ? h + "px" : pn.getStyle("height");
            if(p === "top" || p === "bottom")
            {
                cb.setStyle("width", w);
            }
            else
            {
                cb.setStyle("height", h);
            }
            cb.setStyle("position", "relative");
            cb.setStyle("left", "0px");
            cb.setStyle("top", "0px");
            this.set("graphic", new Y.Graphic());
            this.get("graphic").render(cb);
        },

        /**
         * @protected
         *
         * Gets the default value for the <code>styles</code> attribute. Overrides
         * base implementation.
         *
         * @method _getDefaultStyles
         * @return Object
         */
        _getDefaultStyles: function()
        {
            var axisstyles = {
                majorTicks: {
                    display:"inside",
                    length:4,
                    color:"#dad8c9",
                    weight:1,
                    alpha:1
                },
                minorTicks: {
                    display:"none",
                    length:2,
                    color:"#dad8c9",
                    weight:1
                },
                line: {
                    weight:1,
                    color:"#dad8c9",
                    alpha:1
                },
                majorUnit: {
                    determinant:"count",
                    count:11,
                    distance:75
                },
                top: "0px",
                left: "0px",
                width: "100px",
                height: "100px",
                label: {
                    color:"#808080",
                    alpha: 1,
                    fontSize:"85%",
                    rotation: 0,
                    margin: {
                        top:4,
                        right:4,
                        bottom:4,
                        left:4
                    }
                },
                hideOverlappingLabelTicks: false
            };

            return Y.merge(Y.Renderer.prototype._getDefaultStyles(), axisstyles);
        },

        /**
         * @private
         */
        _handleSizeChange: function(e)
        {
            var attrName = e.attrName,
                pos = this.get("position"),
                vert = pos == "left" || pos == "right",
                cb = this.get("contentBox"),
                hor = pos == "bottom" || pos == "top";
            cb.setStyle("width", this.get("width"));
            cb.setStyle("height", this.get("height"));
            if((hor && attrName == "width") || (vert && attrName == "height"))
            {
                this._drawAxis();
            }
        },

        /**
         * @private
         */
        _layout: null,

        /**
         * @private
         */
        getLayout: function(pos)
        {
            var l;
            switch(pos)
            {
                case "top" :
                    l = new Y.TopAxisLayout({axisRenderer:this});
                break;
                case "bottom" :
                    l = new Y.BottomAxisLayout({axisRenderer:this});
                break;
                case "left" :
                    l = new Y.LeftAxisLayout({axisRenderer:this});
                break;
                case "right" :
                    l = new Y.RightAxisLayout({axisRenderer:this});
                break;
            }
            return l;
        },

        /**
         * @private
         */
        drawLine: function(startPoint, endPoint, line)
        {
            var graphic = this.get("graphic");
            graphic.lineStyle(line.weight, line.color, line.alpha);
            graphic.moveTo(startPoint.x, startPoint.y);
            graphic.lineTo(endPoint.x, endPoint.y);
            graphic.end();
        },

        /**
         * @private
         */
        _drawAxis: function ()
        {
            if(this._drawing)
            {
                this._callLater = true;
                return;
            }
            this._drawing = true;
            this._callLater = false;
            if(this.get("position") != "none")
            {
                var styles = this.get("styles"),
                    majorTickStyles = styles.majorTicks,
                    drawTicks = majorTickStyles.display != "none",
                    tickPoint,
                    majorUnit = styles.majorUnit,
                    len,
                    majorUnitDistance,
                    i = 0,
                    layoutLength,
                    position,
                    lineStart,
                    label,
                    layout = this._layout,
                    labelFunction = this.get("labelFunction"),
                    labelFunctionScope = this.get("labelFunctionScope"),
                    labelFormat = this.get("labelFormat"),
                    graphic = this.get("graphic");
                graphic.clear();
                layout.setTickOffsets();
                layoutLength = this.getLength();
                lineStart = layout.getLineStart();
                len = this.getTotalMajorUnits(majorUnit);
                majorUnitDistance = this.getMajorUnitDistance(len, layoutLength, majorUnit);
                this.set("edgeOffset", this.getEdgeOffset(len, layoutLength) * 0.5);
                tickPoint = this.getFirstPoint(lineStart);
                this.drawLine(lineStart, this.getLineEnd(tickPoint), styles.line);
                if(drawTicks)
                {
                   layout.drawTick(tickPoint, majorTickStyles);
                }
                if(len < 1)
                {
                    this._clearLabelCache();
                    return;
                }
                this._createLabelCache();
                this._tickPoints = [];
                layout.set("maxLabelSize", 0);
                for(; i < len; ++i)
                {
                    if(drawTicks)
                    {
                        layout.drawTick(tickPoint, majorTickStyles);
                    }
                    position = this.getPosition(tickPoint);
                    label = this.getLabel(tickPoint);
                    label.innerHTML = labelFunction.apply(labelFunctionScope, [this.getLabelByIndex(i, len), labelFormat]);
                    tickPoint = this.getNextPoint(tickPoint, majorUnitDistance);
                }
                this._clearLabelCache();
                layout.setSizeAndPosition();
                if(this.get("overlapGraph"))
                {
                   layout.offsetNodeForTick(this.get("contentBox"));
                }
                layout.setCalculatedSize();
                for(i = 0; i < len; ++i)
                {
                    layout.positionLabel(this.get("labels")[i], this._tickPoints[i]);
                }
            }
            this._drawing = false;
            if(this._callLater)
            {
                this._drawAxis();
            }
            else
            {
                this.fire("axisRendered");
            }
        },

        /**
         * @private
         */
        _labels: null,

        /**
         * @private
         */
        _labelCache: null,

        /**
         * @private
         */
        getLabel: function(pt, pos)
        {
            var i,
                label,
                customStyles = {
                    rotation: "rotation",
                    margin: "margin",
                    alpha: "alpha"
                },
                cache = this._labelCache,
                styles = this.get("styles").label;
            if(cache.length > 0)
            {
                label = cache.shift();
            }
            else
            {
                label = document.createElement("span");
                label.style.display = "block";
                label.style.whiteSpace = "nowrap";
                Y.one(label).addClass("axisLabel");
                this.get("contentBox").appendChild(label);
            }
            label.style.position = "absolute";
            this._labels.push(label);
            this._tickPoints.push({x:pt.x, y:pt.y});
            this._layout.updateMaxLabelSize(label);
            for(i in styles)
            {
                if(styles.hasOwnProperty(i) && !customStyles.hasOwnProperty(i))
                {
                    label.style[i] = styles[i];
                }
            }
            return label;
        },

        /**
         * @private
         */
        _createLabelCache: function()
        {
            if(this._labels)
            {
                if(this._labelCache)
                {
                    this._labelCache = this._labels.concat(this._labelCache);
                }
                else
                {
                    this._labelCache = this._labels.concat();
                }
            }
            else
            {
                this._clearLabelCache();
            }
            this._labels = [];
        },

        /**
         * @private
         */
        _clearLabelCache: function()
        {
            if(this._labelCache)
            {
                var len = this._labelCache.length,
                    i = 0,
                    label,
                    labelCache = this._labelCache;
                for(; i < len; ++i)
                {
                    label = labelCache[i];
                    label.parentNode.removeChild(label);
                }
            }
            this._labelCache = [];
        },

        /**
         * @private
         */
        _calculateSizeByTickLength: true,

        /**
         * @private
         */
        getLineEnd: function(pt)
        {
            var w = this.get("width"),
                h = this.get("height"),
                pos = this.get("position");
            if(pos === "top" || pos === "bottom")
            {
                return {x:w, y:pt.y};
            }
            else
            {
                return {x:pt.x, y:h};
            }
        },

        /**
         * @private
         */
        getLength: function()
        {
            var l,
                style = this.get("styles"),
                padding = style.padding,
                w = this.get("width"),
                h = this.get("height"),
                pos = this.get("position");
            if(pos === "top" || pos === "bottom")
            {
                l = w - (padding.left + padding.right);
            }
            else
            {
                l = h - (padding.top + padding.bottom);
            }
            return l;
        },

        /**
         * @private
         */
        getFirstPoint:function(pt)
        {
            var style = this.get("styles"),
                pos = this.get("position"),
                padding = style.padding,
                np = {x:pt.x, y:pt.y};
            if(pos === "top" || pos === "bottom")
            {
                np.x += padding.left + this.get("edgeOffset");
            }
            else
            {
                np.y += this.get("height") - (padding.top + this.get("edgeOffset"));
            }
            return np;
        },

        /**
         * @private
         */
        getNextPoint: function(point, majorUnitDistance)
        {
            var pos = this.get("position");
            if(pos === "top" || pos === "bottom")
            {
                point.x = point.x + majorUnitDistance;
            }
            else
            {
                point.y = point.y - majorUnitDistance;
            }
            return point;
        },

        /**
         * @private
         */
        getLastPoint: function()
        {
            var style = this.get("styles"),
                padding = style.padding,
                w = this.get("width"),
                pos = this.get("position");
            if(pos === "top" || pos === "bottom")
            {
                return {x:w - padding.right, y:padding.top};
            }
            else
            {
                return {x:padding.left, y:padding.top};
            }
        },

        /**
         * @private
         */
        getPosition: function(point)
        {
            var p,
                h = this.get("height"),
                style = this.get("styles"),
                padding = style.padding,
                pos = this.get("position"),
                dataType = this.get("dataType");
            if(pos === "left" || pos === "right")
            {
                //Numeric data on a vertical axis is displayed from bottom to top.
                //Categorical and Timeline data is displayed from top to bottom.
                if(dataType === "numeric")
                {
                    p = (h - (padding.top + padding.bottom)) - (point.y - padding.top);
                }
                else
                {
                    p = point.y - padding.top;
                }
            }
            else
            {
                p = point.x - padding.left;
            }
            return p;
        }
    }, {
        ATTRS:
        {
            /**
             * @protected
             *
             * Difference betweend the first/last tick and edge of axis.
             *
             * @attribute edgeOffset
             * @type Number
             */
            edgeOffset:
            {
                value: 0
            },

            /**
             * The graphic in which the axis line and ticks will be rendered.
             *
             * @attribute graphic
             * @type Graphic
             */
            graphic: {},

            /**
             * Contains the contents of the axis.
             *
             * @attribute node
             * @type HTMLElement
             */
            node: {},

            /**
             * Direction of the axis.
             *
             * @attribute position
             * @type String
             */
            position: {
                lazyAdd: false,

                setOnce: true,

                setter: function(val)
                {
                    if(val == "none")
                    {
                        this.bindUI();
                    }
                    return val;
                }
            },

            /**
             * Distance determined by the tick styles used to calculate the distance between the axis
             * line in relation to the top of the axis.
             *
             * @attribute topTickOffset
             * @type Number
             */
            topTickOffset: {
                value: 0
            },

            /**
             * Distance determined by the tick styles used to calculate the distance between the axis
             * line in relation to the bottom of the axis.
             *
             * @attribute bottomTickOffset
             * @type Number
             */
            bottomTickOffset: {
                value: 0
            },

            /**
             * Distance determined by the tick styles used to calculate the distance between the axis
             * line in relation to the left of the axis.
             *
             * @attribute leftTickOffset
             * @type Number
             */
            leftTickOffset: {
                value: 0
            },

            /**
             * Distance determined by the tick styles used to calculate the distance between the axis
             * line in relation to the right side of the axis.
             *
             * @attribute rightTickOffset
             * @type Number
             */
            rightTickOffset: {
                value: 0
            },

            /**
             * Collection of labels used to render the axis.
             *
             * @attribute labels
             * @type Array
             */
            labels: {
                readOnly: true,
                getter: function()
                {
                    return this._labels;
                }
            },

            /**
             * Collection of points used for placement of labels and ticks along the axis.
             *
             * @attribute tickPoints
             * @type Array
             */
            tickPoints: {
                readOnly: true,

                getter: function()
                {
                    if(this.get("position") == "none")
                    {
                        return this.get("styles").majorUnit.count;
                    }
                    return this._tickPoints;
                }
            },

            /**
             * Indicates whether the axis overlaps the graph. If an axis is the inner most axis on a given
             * position and the tick position is inside or cross, the axis will need to overlap the graph.
             *
             * @attribute overlapGraph
             * @type Boolean
             */
            overlapGraph: {
                value:true,

                validator: function(val)
                {
                    return Y.Lang.isBoolean(val);
                }
            },

            /**
             * Object which should have by the labelFunction
             *
             * @attribute labelFunctionScope
             * @type Object
             */
            labelFunctionScope: {}

            /**
             * Style properties used for drawing an axis. This attribute is inherited from <code>Renderer</code>. Below are the default values:
             *  <dl>
             *      <dt>majorTicks</dt><dd>Properties used for drawing ticks.
             *          <dl>
             *              <dt>display</dt><dd>Position of the tick. Possible values are <code>inside</code>, <code>outside</code>, <code>cross</code> and <code>none</code>. The
             *              default value is <code>inside</code>.</dd>
             *              <dt>length</dt><dd>The length (in pixels) of the tick. The default value is 4.</dd>
             *              <dt>color</dt><dd>The color of the tick. The default value is <code>#dad8c9</code></dd>
             *              <dt>weight</dt><dd>Number indicating the width of the tick. The default value is 1.</dd>
             *              <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the tick. The default value is 1.</dd>
             *          </dl>
             *      </dd>
             *      <dt>line</dt><dd>Properties used for drawing the axis line.
             *          <dl>
             *              <dt>weight</dt><dd>Number indicating the width of the axis line. The default value is 1.</dd>
             *              <dt>color</dt><dd>The color of the axis line. The default value is <code>#dad8c9</code>.</dd>
             *              <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the tick. The default value is 1.</dd>
             *          </dl>
             *      </dd>
             *      <dt>majorUnit</dt><dd>Properties used to calculate the <code>majorUnit</code> for the axis.
             *          <dl>
             *              <dt>determinant</dt><dd>The algorithm used for calculating distance between ticks. The possible options are <code>count</code> and <code>distance</code>. If
             *              the <code>determinant</code> is <code>count</code>, the axis ticks will spaced so that a specified number of ticks appear on the axis. If the <code>determinant</code>
             *              is <code>distance</code>, the axis ticks will spaced out according to the specified distance. The default value is <code>count</code>.</dd>
             *              <dt>count</dt><dd>Number of ticks to appear on the axis when the <code>determinant</code> is <code>count</code>. The default value is 11.</dd>
             *              <dt>distance</dt><dd>The distance (in pixels) between ticks when the <code>determinant</code> is <code>distance</code>. The default value is 75.</dd>
             *          </dl>
             *      </dd>
             *      <dt>label</dt><dd>Properties and styles applied to the axis labels.
             *          <dl>
             *              <dt>color</dt><dd>The color of the labels. The default value is <code>#808080</code>.</dd>
             *              <dt>alpha</dt><dd>Number between 0 and 1 indicating the opacity of the labels. The default value is 1.</dd>
             *              <dt>fontSize</dt><dd>The font-size of the labels. The default value is 85%</dd>
             *              <dt>rotation</dt><dd>The rotation, in degrees (between -90 and 90) of the labels. The default value is 0.</dd>
             *              <dt>margin</dt><dd>The distance between the label and the axis/tick. Depending on the position of the <code>Axis</code>, only one of the properties used.
             *                  <dl>
             *                      <dt>top</dt><dd>Pixel value used for an axis with a <code>position</code> of <code>bottom</code>. The default value is 4.</dd>
             *                      <dt>right</dt><dd>Pixel value used for an axis with a <code>position</code> of <code>left</code>. The default value is 4.</dd>
             *                      <dt>bottom</dt><dd>Pixel value used for an axis with a <code>position</code> of <code>top</code>. The default value is 4.</dd>
             *                      <dt>left</dt><dd>Pixel value used for an axis with a <code>position</code> of <code>right</code>. The default value is 4.</dd>
             *                  </dl>
             *              </dd>
             *          </dl>
             *      </dd>
             *  </dl>
             *
             * @attribute styles
             * @type Object
             */
        }
    });

Copyright © 2011 Yahoo! Inc. All rights reserved.