3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
16 * @class Ext.chart.Legend
18 * Defines a legend for a chart's series.
19 * The 'chart' member must be set prior to rendering.
20 * The legend class displays a list of legend items each of them related with a
21 * series being rendered. In order to render the legend item of the proper series
22 * the series configuration object must have `showInSeries` set to true.
24 * The legend configuration object accepts a `position` as parameter.
25 * The `position` parameter can be `left`, `right`
26 * `top` or `bottom`. For example:
34 var store = Ext.create('Ext.data.JsonStore', {
35 fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
37 {'name':'metric one', 'data1':10, 'data2':12, 'data3':14, 'data4':8, 'data5':13},
38 {'name':'metric two', 'data1':7, 'data2':8, 'data3':16, 'data4':10, 'data5':3},
39 {'name':'metric three', 'data1':5, 'data2':2, 'data3':14, 'data4':12, 'data5':7},
40 {'name':'metric four', 'data1':2, 'data2':14, 'data3':6, 'data4':1, 'data5':23},
41 {'name':'metric five', 'data1':27, 'data2':38, 'data3':36, 'data4':13, 'data5':33}
45 Ext.create('Ext.chart.Chart', {
46 renderTo: Ext.getBody(),
60 fields: ['data1', 'data2', 'data3', 'data4', 'data5'],
61 title: 'Sample Values',
71 adjustMinimumByMajorUnit: 0
76 title: 'Sample Metrics',
89 yField: ['data1', 'data2', 'data3', 'data4', 'data5'],
98 Ext.define('Ext.chart.Legend', {
100 /* Begin Definitions */
102 requires: ['Ext.chart.LegendItem'],
104 /* End Definitions */
107 * @cfg {Boolean} visible
108 * Whether or not the legend should be displayed.
113 * @cfg {String} position
114 * The position of the legend in relation to the chart. One of: "top",
115 * "bottom", "left", "right", or "float". If set to "float", then the legend
116 * box will be positioned at the point denoted by the x and y parameters.
122 * X-position of the legend box. Used directly if position is set to "float", otherwise
123 * it will be calculated dynamically.
129 * Y-position of the legend box. Used directly if position is set to "float", otherwise
130 * it will be calculated dynamically.
135 * @cfg {String} labelFont
136 * Font to be used for the legend labels, eg '12px Helvetica'
138 labelFont: '12px Helvetica, sans-serif',
141 * @cfg {String} boxStroke
142 * Style of the stroke for the legend box
147 * @cfg {String} boxStrokeWidth
148 * Width of the stroke for the legend box
153 * @cfg {String} boxFill
154 * Fill style for the legend box
159 * @cfg {Number} itemSpacing
160 * Amount of space between legend items
165 * @cfg {Number} padding
166 * Amount of padding between the legend box's border and its items
176 * @cfg {Number} boxZIndex
177 * Sets the z-index for the legend. Defaults to 100.
182 * Creates new Legend.
183 * @param {Object} config (optional) Config object.
185 constructor: function(config) {
188 Ext.apply(me, config);
192 * Whether the legend box is oriented vertically, i.e. if it is on the left or right side or floating.
195 me.isVertical = ("left|right|float".indexOf(me.position) !== -1);
197 // cache these here since they may get modified later on
203 * @private Create all the sprites for the legend
208 if (!me.created && me.isDisplayed()) {
212 // Listen for changes to series titles to trigger regeneration of the legend
213 me.chart.series.each(function(series) {
214 series.on('titlechange', function() {
223 * @private Determine whether the legend should be displayed. Looks at the legend's 'visible' config,
224 * and also the 'showInLegend' config for each of the series.
226 isDisplayed: function() {
227 return this.visible && this.chart.series.findIndex('showInLegend', true) !== -1;
231 * @private Create the series markers and labels
233 createItems: function() {
236 surface = chart.surface,
238 padding = me.padding,
239 itemSpacing = me.itemSpacing,
245 vertical = me.isVertical,
251 len = items ? items.length : 0,
252 x, y, spacing, item, bbox, height, width;
254 //remove all legend items
256 for (; i < len; i++) {
262 // Create all the item labels, collecting their dimensions and positioning each one
263 // properly in relation to the previous item
264 chart.series.each(function(series, i) {
265 if (series.showInLegend) {
266 Ext.each([].concat(series.yField), function(field, j) {
267 item = Ext.create('Ext.chart.LegendItem', {
270 surface: chart.surface,
273 bbox = item.getBBox();
275 //always measure from x=0, since not all markers go all the way to the left
277 height = bbox.height;
280 spacing = vertical ? padding + height / 2 : padding;
283 spacing = itemSpacing / (vertical ? 2 : 1);
285 // Set the item's position relative to the legend box
286 item.x = mfloor(vertical ? padding : totalWidth + spacing);
287 item.y = mfloor(vertical ? totalHeight + spacing : padding + height / 2);
289 // Collect cumulative dimensions
290 totalWidth += width + spacing;
291 totalHeight += height + spacing;
292 maxWidth = mmax(maxWidth, width);
293 maxHeight = mmax(maxHeight, height);
300 // Store the collected dimensions for later
301 me.width = mfloor((vertical ? maxWidth : totalWidth) + padding * 2);
302 if (vertical && items.length === 1) {
305 me.height = mfloor((vertical ? totalHeight - spacingOffset * spacing : maxHeight) + (padding * 2));
306 me.itemHeight = maxHeight;
310 * @private Get the bounds for the legend's outer box
312 getBBox: function() {
315 x: Math.round(me.x) - me.boxStrokeWidth / 2,
316 y: Math.round(me.y) - me.boxStrokeWidth / 2,
323 * @private Create the box around the legend items
325 createBox: function() {
327 box = me.boxSprite = me.chart.surface.add(Ext.apply({
329 stroke: me.boxStroke,
330 "stroke-width": me.boxStrokeWidth,
338 * @private Update the position of all the legend's sprites to match its current x/y values
340 updatePosition: function() {
343 legendWidth = me.width,
344 legendHeight = me.height,
345 padding = me.padding,
347 chartBBox = chart.chartBBox,
348 insets = chart.insetPadding,
349 chartWidth = chartBBox.width - (insets * 2),
350 chartHeight = chartBBox.height - (insets * 2),
351 chartX = chartBBox.x + insets,
352 chartY = chartBBox.y + insets,
353 surface = chart.surface,
356 if (me.isDisplayed()) {
357 // Find the position based on the dimensions
358 switch(me.position) {
361 y = mfloor(chartY + chartHeight / 2 - legendHeight / 2);
364 x = mfloor(surface.width - legendWidth) - insets;
365 y = mfloor(chartY + chartHeight / 2 - legendHeight / 2);
368 x = mfloor(chartX + chartWidth / 2 - legendWidth / 2);
372 x = mfloor(chartX + chartWidth / 2 - legendWidth / 2);
373 y = mfloor(surface.height - legendHeight) - insets;
376 x = mfloor(me.origX) + insets;
377 y = mfloor(me.origY) + insets;
382 // Update the position of each item
383 Ext.each(me.items, function(item) {
384 item.updatePosition();
386 // Update the position of the outer box
387 me.boxSprite.setAttributes(me.getBBox(), true);