    /**
     * @class Ext.chart.Highlight
     * A mixin providing highlight functionality for Ext.chart.series.Series.
     */
    Ext.define('Ext.chart.Highlight', {

        /* Begin Definitions */

        requires: ['Ext.fx.Anim'],

        /* End Definitions */

        /**
         * @cfg {Boolean/Object} [highlight=false] Set to `true` to enable highlighting using the {@link #highlightCfg default highlight attributes}.
         *
         * Can also be an object with style properties (i.e fill, stroke, stroke-width, radius) which are may override the {@link #highlightCfg default highlight attributes}.
         */
        highlight: false,

        /**
         * @property {Object} highlightCfg The default properties to apply as a highight. Value is
         *
         *    {
         *        fill: '#fdd',
         *        "stroke-width": 5,
         *        stroke: "#f55'
         *    }
         */
        highlightCfg : {
            fill: '#fdd',
            "stroke-width": 5,
            stroke: '#f55'
        },

        constructor: function(config) {
            // If configured with a highlight object, apply to to *a local copy of* this class's highlightCfg. Do not mutate the prototype's copy.
            if (config.highlight && (typeof config.highlight !== 'boolean')) { //is an object
                this.highlightCfg = Ext.merge({}, this.highlightCfg, config.highlight);
            }
        },

        /**
         * Highlight the given series item.
         * @param {Object} item Info about the item; same format as returned by #getItemForPoint.
         */
        highlightItem: function(item) {
            if (!item) {
                return;
            }

            var me = this,
                sprite = item.sprite,
                opts = Ext.merge({}, me.highlightCfg, me.highlight),
                surface = me.chart.surface,
                animate = me.chart.animate,
                p, from, to, pi;

            if (!me.highlight || !sprite || sprite._highlighted) {
                return;
            }
            if (sprite._anim) {
                sprite._anim.paused = true;
            }
            sprite._highlighted = true;
            if (!sprite._defaults) {
                sprite._defaults = Ext.apply({}, sprite.attr);
                from = {};
                to = {};
                // TODO: Clean up code below.
                for (p in opts) {
                    if (! (p in sprite._defaults)) {
                        sprite._defaults[p] = surface.availableAttrs[p];
                    }
                    from[p] = sprite._defaults[p];
                    to[p] = opts[p];
                    if (Ext.isObject(opts[p])) {
                        from[p] = {};
                        to[p] = {};
                        Ext.apply(sprite._defaults[p], sprite.attr[p]);
                        Ext.apply(from[p], sprite._defaults[p]);
                        for (pi in sprite._defaults[p]) {
                            if (! (pi in opts[p])) {
                                to[p][pi] = from[p][pi];
                            } else {
                                to[p][pi] = opts[p][pi];
                            }
                        }
                        for (pi in opts[p]) {
                            if (! (pi in to[p])) {
                                to[p][pi] = opts[p][pi];
                            }
                        }
                    }
                }
                sprite._from = from;
                sprite._to = to;
                sprite._endStyle = to;
            }
            if (animate) {
                sprite._anim = new Ext.fx.Anim({
                    target: sprite,
                    from: sprite._from,
                    to: sprite._to,
                    duration: 150
                });
            } else {
                sprite.setAttributes(sprite._to, true);
            }
        },

        /**
         * Un-highlight any existing highlights
         */
        unHighlightItem: function() {
            if (!this.highlight || !this.items) {
                return;
            }

            var me = this,
                items = me.items,
                len = items.length,
                opts = Ext.merge({}, me.highlightCfg, me.highlight),
                animate = me.chart.animate,
                i = 0,
                obj, p, sprite;
            for (; i < len; i++) {
                if (!items[i]) {
                    continue;
                }
                sprite = items[i].sprite;
                if (sprite && sprite._highlighted) {
                    if (sprite._anim) {
                        sprite._anim.paused = true;
                    }
                    obj = {};
                    for (p in opts) {
                        if (Ext.isObject(sprite._defaults[p])) {
                            obj[p] = Ext.apply({}, sprite._defaults[p]);
                        }
                        else {
                            obj[p] = sprite._defaults[p];
                        }
                    }
                    if (animate) {
                        //sprite._to = obj;
                        sprite._endStyle = obj;
                        sprite._anim = new Ext.fx.Anim({
                            target: sprite,
                            to: obj,
                            duration: 150
                        });
                    }
                    else {
                        sprite.setAttributes(obj, true);
                    }
                    delete sprite._highlighted;
                    //delete sprite._defaults;
                }
            }
        },

        cleanHighlights: function() {
            if (!this.highlight) {
                return;
            }

            var group = this.group,
                markerGroup = this.markerGroup,
                i = 0,
                l;
            for (l = group.getCount(); i < l; i++) {
                delete group.getAt(i)._defaults;
            }
            if (markerGroup) {
                for (l = markerGroup.getCount(); i < l; i++) {
                    delete markerGroup.getAt(i)._defaults;
                }
            }
        }
    });