    /**
     * @class Ext.chart.LegendItem
     * A single item of a legend (marker plus label)
     */
    Ext.define('Ext.chart.LegendItem', {

        /* Begin Definitions */

        extend: 'Ext.draw.CompositeSprite',

        requires: ['Ext.chart.Shape'],

        /* End Definitions */

        // Position of the item, relative to the upper-left corner of the legend box
        x: 0,
        y: 0,
        zIndex: 500,

        // checks to make sure that a unit size follows the bold keyword in the font style value
        boldRe: /bold\s\d{1,}.*/i,

        constructor: function(config) {
            this.callParent(arguments);
            this.createLegend(config);
        },

        /**
         * Creates all the individual sprites for this legend item
         */
        createLegend: function(config) {
            var me = this,
                index = config.yFieldIndex,
                series = me.series,
                seriesType = series.type,
                idx = me.yFieldIndex,
                legend = me.legend,
                surface = me.surface,
                refX = legend.x + me.x,
                refY = legend.y + me.y,
                bbox, z = me.zIndex,
                markerConfig, label, mask,
                radius, toggle = false,
                seriesStyle = Ext.apply(series.seriesStyle, series.style);

            function getSeriesProp(name) {
                var val = series[name];
                return (Ext.isArray(val) ? val[idx] : val);
            }

            label = me.add('label', surface.add({
                type: 'text',
                x: 20,
                y: 0,
                zIndex: (z || 0) + 2,
                fill: legend.labelColor,
                font: legend.labelFont,
                text: getSeriesProp('title') || getSeriesProp('yField'),
                style: {
                    'cursor': 'pointer'
                }
            }));

            // Line series - display as short line with optional marker in the middle
            if (seriesType === 'line' || seriesType === 'scatter') {
                if(seriesType === 'line') {
                    me.add('line', surface.add({
                        type: 'path',
                        path: 'M0.5,0.5L16.5,0.5',
                        zIndex: (z || 0) + 2,
                        "stroke-width": series.lineWidth,
                        "stroke-linejoin": "round",
                        "stroke-dasharray": series.dash,
                        stroke: seriesStyle.stroke || series.getLegendColor(index) || '#000',
                        style: {
                            cursor: 'pointer'
                        }
                    }));
                }
                if (series.showMarkers || seriesType === 'scatter') {
                    markerConfig = Ext.apply(series.markerStyle, series.markerConfig || {}, {
                        fill: series.getLegendColor(index)
                    });
                    me.add('marker', Ext.chart.Shape[markerConfig.type](surface, {
                        fill: markerConfig.fill,
                        x: 8.5,
                        y: 0.5,
                        zIndex: (z || 0) + 2,
                        radius: markerConfig.radius || markerConfig.size,
                        style: {
                            cursor: 'pointer'
                        }
                    }));
                }
            }
            // All other series types - display as filled box
            else {
                me.add('box', surface.add({
                    type: 'rect',
                    zIndex: (z || 0) + 2,
                    x: 0,
                    y: 0,
                    width: 12,
                    height: 12,
                    fill: series.getLegendColor(index),
                    style: {
                        cursor: 'pointer'
                    }
                }));
            }

            me.setAttributes({
                hidden: false
            }, true);

            bbox = me.getBBox();

            mask = me.add('mask', surface.add({
                type: 'rect',
                x: bbox.x,
                y: bbox.y,
                width: bbox.width || 20,
                height: bbox.height || 20,
                zIndex: (z || 0) + 1,
                fill: me.legend.boxFill,
                style: {
                    'cursor': 'pointer'
                }
            }));

            //add toggle listener
            me.on('mouseover', function() {
                label.setStyle({
                    'font-weight': 'bold'
                });
                mask.setStyle({
                    'cursor': 'pointer'
                });
                series._index = index;
                series.highlightItem();
            }, me);

            me.on('mouseout', function() {
                label.setStyle({
                    'font-weight': legend.labelFont && me.boldRe.test(legend.labelFont) ? 'bold' : 'normal'
                });
                series._index = index;
                series.unHighlightItem();
            }, me);

            if (!series.visibleInLegend(index)) {
                toggle = true;
                label.setAttributes({
                   opacity: 0.5
                }, true);
            }

            me.on('mousedown', function() {
                if (!toggle) {
                    series.hideAll(index);
                    label.setAttributes({
                        opacity: 0.5
                    }, true);
                } else {
                    series.showAll(index);
                    label.setAttributes({
                        opacity: 1
                    }, true);
                }
                toggle = !toggle;
                me.legend.chart.redraw();
            }, me);
            me.updatePosition({x:0, y:0}); //Relative to 0,0 at first so that the bbox is calculated correctly
        },

        /**
         * Update the positions of all this item's sprites to match the root position
         * of the legend box.
         * @param {Object} relativeTo (optional) If specified, this object's 'x' and 'y' values will be used
         *                 as the reference point for the relative positioning. Defaults to the Legend.
         */
        updatePosition: function(relativeTo) {
            var me = this,
                items = me.items,
                ln = items.length,
                i = 0,
                item;
            if (!relativeTo) {
                relativeTo = me.legend;
            }
            for (; i < ln; i++) {
                item = items[i];
                switch (item.type) {
                    case 'text':
                        item.setAttributes({
                            x: 20 + relativeTo.x + me.x,
                            y: relativeTo.y + me.y
                        }, true);
                        break;
                    case 'rect':
                        item.setAttributes({
                            translate: {
                                x: relativeTo.x + me.x,
                                y: relativeTo.y + me.y - 6
                            }
                        }, true);
                        break;
                    default:
                        item.setAttributes({
                            translate: {
                                x: relativeTo.x + me.x,
                                y: relativeTo.y + me.y
                            }
                        }, true);
                }
            }
        }
    });