Version 3.18.1
Show:

File: charts/js/PieChart.js

            /**
             * The PieChart class creates a pie chart
             *
             * @class PieChart
             * @extends ChartBase
             * @constructor
             * @submodule charts-base
             */
            Y.PieChart = Y.Base.create("pieChart", Y.Widget, [Y.ChartBase], {
                /**
                 * Calculates and returns a `seriesCollection`.
                 *
                 * @method _getSeriesCollection
                 * @return Array
                 * @private
                 */
                _getSeriesCollection: function()
                {
                    if(this._seriesCollection)
                    {
                        return this._seriesCollection;
                    }
                    var axes = this.get("axes"),
                        sc = [],
                        seriesKeys,
                        i = 0,
                        l,
                        type = this.get("type"),
                        key,
                        catAxis = "categoryAxis",
                        catKey = "categoryKey",
                        valAxis = "valueAxis",
                        seriesKey = "valueKey";
                    if(axes)
                    {
                        seriesKeys = axes.values.get("keyCollection");
                        key = axes.category.get("keyCollection")[0];
                        l = seriesKeys.length;
                        for(; i < l; ++i)
                        {
                            sc[i] = {type:type};
                            sc[i][catAxis] = "category";
                            sc[i][valAxis] = "values";
                            sc[i][catKey] = key;
                            sc[i][seriesKey] = seriesKeys[i];
                        }
                    }
                    this._seriesCollection = sc;
                    return sc;
                },
            
                /**
                 * Creates `Axis` instances.
                 *
                 * @method _parseAxes
                 * @param {Object} val Object containing `Axis` instances or objects in which to construct `Axis` instances.
                 * @return Object
                 * @private
                 */
                _parseAxes: function(hash)
                {
                    if(!this._axes)
                    {
                        this._axes = {};
                    }
                    var i, pos, axis, dh, config, AxisClass,
                        type = this.get("type"),
                        w = this.get("width"),
                        h = this.get("height"),
                        node = Y.Node.one(this._parentNode);
                    if(!w)
                    {
                        this.set("width", node.get("offsetWidth"));
                        w = this.get("width");
                    }
                    if(!h)
                    {
                        this.set("height", node.get("offsetHeight"));
                        h = this.get("height");
                    }
                    for(i in hash)
                    {
                        if(hash.hasOwnProperty(i))
                        {
                            dh = hash[i];
                            pos = type === "pie" ? "none" : dh.position;
                            AxisClass = this._getAxisClass(dh.type);
                            config = {dataProvider:this.get("dataProvider")};
                            if(dh.hasOwnProperty("roundingUnit"))
                            {
                                config.roundingUnit = dh.roundingUnit;
                            }
                            config.keys = dh.keys;
                            config.width = w;
                            config.height = h;
                            config.position = pos;
                            config.styles = dh.styles;
                            axis = new AxisClass(config);
                            axis.on("axisRendered", Y.bind(this._itemRendered, this));
                            this._axes[i] = axis;
                        }
                    }
                },
            
                /**
                 * Adds axes to the chart.
                 *
                 * @method _addAxes
                 * @private
                 */
                _addAxes: function()
                {
                    var axes = this.get("axes"),
                        i,
                        axis,
                        p;
                    if(!axes)
                    {
                        this.set("axes", this._getDefaultAxes());
                        axes = this.get("axes");
                    }
                    if(!this._axesCollection)
                    {
                        this._axesCollection = [];
                    }
                    for(i in axes)
                    {
                        if(axes.hasOwnProperty(i))
                        {
                            axis = axes[i];
                            p = axis.get("position");
                            if(!this.get(p + "AxesCollection"))
                            {
                                this.set(p + "AxesCollection", [axis]);
                            }
                            else
                            {
                                this.get(p + "AxesCollection").push(axis);
                            }
                            this._axesCollection.push(axis);
                        }
                    }
                },
            
                /**
                 * Renders the Graph.
                 *
                 * @method _addSeries
                 * @private
                 */
                _addSeries: function()
                {
                    var graph = this.get("graph"),
                        seriesCollection = this.get("seriesCollection");
                    this._parseSeriesAxes(seriesCollection);
                    graph.set("showBackground", false);
                    graph.set("width", this.get("width"));
                    graph.set("height", this.get("height"));
                    graph.set("seriesCollection", seriesCollection);
                    this._seriesCollection = graph.get("seriesCollection");
                    graph.render(this.get("contentBox"));
                },
            
                /**
                 * Parse and sets the axes for the chart.
                 *
                 * @method _parseSeriesAxes
                 * @param {Array} c A collection `PieSeries` instance.
                 * @private
                 */
                _parseSeriesAxes: function(c)
                {
                    var i = 0,
                        len = c.length,
                        s,
                        axes = this.get("axes"),
                        axis;
                    for(; i < len; ++i)
                    {
                        s = c[i];
                        if(s)
                        {
                            //If series is an actual series instance,
                            //replace axes attribute string ids with axes
                            if(s instanceof Y.PieSeries)
                            {
                                axis = s.get("categoryAxis");
                                if(axis && !(axis instanceof Y.Axis))
                                {
                                    s.set("categoryAxis", axes[axis]);
                                }
                                axis = s.get("valueAxis");
                                if(axis && !(axis instanceof Y.Axis))
                                {
                                    s.set("valueAxis", axes[axis]);
                                }
                                continue;
                            }
                            s.categoryAxis = axes.category;
                            s.valueAxis = axes.values;
                            if(!s.type)
                            {
                                s.type = this.get("type");
                            }
                        }
                    }
                },
            
                /**
                 * Generates and returns a key-indexed object containing `Axis` instances or objects used to create `Axis` instances.
                 *
                 * @method _getDefaultAxes
                 * @return Object
                 * @private
                 */
                _getDefaultAxes: function()
                {
                    var catKey = this.get("categoryKey"),
                        seriesKeys = this.get("seriesKeys").concat(),
                        seriesAxis = "numeric";
                    return {
                        values:{
                            keys:seriesKeys,
                            type:seriesAxis
                        },
                        category:{
                            keys:[catKey],
                            type:this.get("categoryType")
                        }
                    };
                },
            
                /**
                 * Returns an object literal containing a categoryItem and a valueItem for a given series index.
                 *
                 * @method getSeriesItem
                 * @param series Reference to a series.
                 * @param index Index of the specified item within a series.
                 * @return Object
                 */
                getSeriesItems: function(series, index)
                {
                    var categoryItem = {
                            axis: series.get("categoryAxis"),
                            key: series.get("categoryKey"),
                            displayName: series.get("categoryDisplayName")
                        },
                        valueItem = {
                            axis: series.get("valueAxis"),
                            key: series.get("valueKey"),
                            displayName: series.get("valueDisplayName")
                        };
                    categoryItem.value = categoryItem.axis.getKeyValueAt(categoryItem.key, index);
                    valueItem.value = valueItem.axis.getKeyValueAt(valueItem.key, index);
                    return {category:categoryItem, value:valueItem};
                },
            
                /**
                 * Handler for sizeChanged event.
                 *
                 * @method _sizeChanged
                 * @param {Object} e Event object.
                 * @private
                 */
                _sizeChanged: function()
                {
                    this._redraw();
                },
            
                /**
                 * Redraws the chart instance.
                 *
                 * @method _redraw
                 * @private
                 */
                _redraw: function()
                {
                    var graph = this.get("graph"),
                        w = this.get("width"),
                        h = this.get("height"),
                        dimension;
                    if(graph)
                    {
                        dimension = Math.min(w, h);
                        graph.set("width", dimension);
                        graph.set("height", dimension);
                    }
                },
            
                /**
                 * Formats tooltip text for a pie chart.
                 *
                 * @method _tooltipLabelFunction
                 * @param {Object} categoryItem An object containing the following:
                 *  <dl>
                 *      <dt>axis</dt><dd>The axis to which the category is bound.</dd>
                 *      <dt>displayName</dt><dd>The display name set to the category (defaults to key if not provided)</dd>
                 *      <dt>key</dt><dd>The key of the category.</dd>
                 *      <dt>value</dt><dd>The value of the category</dd>
                 *  </dl>
                 * @param {Object} valueItem An object containing the following:
                 *  <dl>
                 *      <dt>axis</dt><dd>The axis to which the item's series is bound.</dd>
                 *      <dt>displayName</dt><dd>The display name of the series. (defaults to key if not provided)</dd>
                 *      <dt>key</dt><dd>The key for the series.</dd>
                 *      <dt>value</dt><dd>The value for the series item.</dd>
                 *  </dl>
                 * @param {Number} itemIndex The index of the item within the series.
                 * @param {CartesianSeries} series The `PieSeries` instance of the item.
                 * @return {HTMLElement}
                 * @private
                 */
                _tooltipLabelFunction: function(categoryItem, valueItem, itemIndex, series)
                {
                    var msg = DOCUMENT.createElement("div"),
                        total = series.getTotalValues(),
                        pct = Math.round((valueItem.value / total) * 10000)/100;
                    msg.appendChild(DOCUMENT.createTextNode(categoryItem.displayName +
                    ": " + categoryItem.axis.get("labelFunction").apply(this, [categoryItem.value, categoryItem.axis.get("labelFormat")])));
                    msg.appendChild(DOCUMENT.createElement("br"));
                    msg.appendChild(DOCUMENT.createTextNode(valueItem.displayName +
                    ": " + valueItem.axis.get("labelFunction").apply(this, [valueItem.value, valueItem.axis.get("labelFormat")])));
                    msg.appendChild(DOCUMENT.createElement("br"));
                    msg.appendChild(DOCUMENT.createTextNode(pct + "%"));
                    return msg;
                },
            
                /**
                 * Returns the appropriate message based on the key press.
                 *
                 * @method _getAriaMessage
                 * @param {Number} key The keycode that was pressed.
                 * @return String
                 */
                _getAriaMessage: function(key)
                {
                    var msg = "",
                        categoryItem,
                        items,
                        series,
                        valueItem,
                        seriesIndex = 0,
                        itemIndex = this._itemIndex,
                        len,
                        total,
                        pct,
                        markers;
                    series = this.getSeries(parseInt(seriesIndex, 10));
                    markers = series.get("markers");
                    len = markers && markers.length ? markers.length : 0;
                    if(key === 37)
                    {
                        itemIndex = itemIndex > 0 ? itemIndex - 1 : len - 1;
                    }
                    else if(key === 39)
                    {
                        itemIndex = itemIndex >= len - 1 ? 0 : itemIndex + 1;
                    }
                    this._itemIndex = itemIndex;
                    items = this.getSeriesItems(series, itemIndex);
                    categoryItem = items.category;
                    valueItem = items.value;
                    total = series.getTotalValues();
                    pct = Math.round((valueItem.value / total) * 10000)/100;
                    if(categoryItem && valueItem)
                    {
                        msg += categoryItem.displayName +
                            ": " +
                            categoryItem.axis.formatLabel.apply(this, [categoryItem.value, categoryItem.axis.get("labelFormat")]) +
                            ", ";
                        msg += valueItem.displayName +
                            ": " + valueItem.axis.formatLabel.apply(this, [valueItem.value, valueItem.axis.get("labelFormat")]) +
                            ", ";
                        msg += "Percent of total " + valueItem.displayName + ": " + pct + "%,";
                    }
                    else
                    {
                        msg += "No data available,";
                    }
                    msg += (itemIndex + 1) + " of " + len + ". ";
                    return msg;
                },
            
                /**
                 * Destructor implementation for the PieChart class.
                 *
                 * @method destructor
                 * @protected
                 */
                destructor: function()
                {
                    var series,
                        axis,
                        tooltip = this.get("tooltip"),
                        tooltipNode = tooltip.node,
                        graph = this.get("graph"),
                        axesCollection = this._axesCollection,
                        seriesCollection = this.get("seriesCollection");
                    while(seriesCollection.length > 0)
                    {
                        series = seriesCollection.shift();
                        series.destroy(true);
                    }
                    while(axesCollection.length > 0)
                    {
                        axis = axesCollection.shift();
                        if(axis instanceof Y.Axis)
                        {
                            axis.destroy(true);
                        }
                    }
                    if(this._description)
                    {
                        this._description.empty();
                        this._description.remove(true);
                    }
                    if(this._liveRegion)
                    {
                        this._liveRegion.empty();
                        this._liveRegion.remove(true);
                    }
                    if(graph)
                    {
                        graph.destroy(true);
                    }
                    if(tooltipNode)
                    {
                        tooltipNode.empty();
                        tooltipNode.remove(true);
                    }
                }
            }, {
                ATTRS: {
                    /**
                     * Sets the aria description for the chart.
                     *
                     * @attribute ariaDescription
                     * @type String
                     */
                    ariaDescription: {
                        value: "Use the left and right keys to navigate through items.",
            
                        setter: function(val)
                        {
                            if(this._description)
                            {
                                this._description.set("text", val);
                            }
                            return val;
                        }
                    },
            
                    /**
                     * Axes to appear in the chart.
                     *
                     * @attribute axes
                     * @type Object
                     */
                    axes: {
                        getter: function()
                        {
                            return this._axes;
                        },
            
                        setter: function(val)
                        {
                            this._parseAxes(val);
                        }
                    },
            
                    /**
                     * Collection of series to appear on the chart. This can be an array of Series instances or object literals
                     * used to describe a Series instance.
                     *
                     * @attribute seriesCollection
                     * @type Array
                     */
                    seriesCollection: {
                        lazyAdd: false,
            
                        getter: function()
                        {
                            return this._getSeriesCollection();
                        },
            
                        setter: function(val)
                        {
                            return this._setSeriesCollection(val);
                        }
                    },
            
                    /**
                     * Type of chart when there is no series collection specified.
                     *
                     * @attribute type
                     * @type String
                     */
                    type: {
                        value: "pie"
                    }
                }
            });