Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / src / chart / LegendItem.js
diff --git a/src/chart/LegendItem.js b/src/chart/LegendItem.js
new file mode 100644 (file)
index 0000000..9ce396a
--- /dev/null
@@ -0,0 +1,211 @@
+/**
+ * @class Ext.chart.LegendItem
+ * @extends Ext.draw.CompositeSprite
+ * A single item of a legend (marker plus label)
+ * @constructor
+ */
+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,
+
+    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,
+            font: legend.labelFont,
+            text: getSeriesProp('title') || getSeriesProp('yField')
+        }));
+
+        // 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,
+                    "stroke-width": series.lineWidth,
+                    "stroke-linejoin": "round",
+                    "stroke-dasharray": series.dash,
+                    stroke: seriesStyle.stroke || '#000',
+                    style: {
+                        cursor: 'pointer'
+                    }
+                }));
+            }
+            if (series.showMarkers || seriesType === 'scatter') {
+                markerConfig = Ext.apply(series.markerStyle, series.markerConfig || {});
+                me.add('marker', Ext.chart.Shape[markerConfig.type](surface, {
+                    fill: markerConfig.fill,
+                    x: 8.5,
+                    y: 0.5,
+                    zIndex: z,
+                    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,
+                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) + 1000,
+            fill: '#f00',
+            opacity: 0,
+            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': '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();
+                label.setAttributes({
+                    opacity: 0.5
+                }, true);
+            } else {
+                series.showAll();
+                label.setAttributes({
+                    opacity: 1
+                }, true);
+            }
+            toggle = !toggle;
+        }, 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);
+            }
+        }
+    }
+});
\ No newline at end of file