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:
35 * var store = Ext.create('Ext.data.JsonStore', {
36 * fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
38 * { 'name': 'metric one', 'data1': 10, 'data2': 12, 'data3': 14, 'data4': 8, 'data5': 13 },
39 * { 'name': 'metric two', 'data1': 7, 'data2': 8, 'data3': 16, 'data4': 10, 'data5': 3 },
40 * { 'name': 'metric three', 'data1': 5, 'data2': 2, 'data3': 14, 'data4': 12, 'data5': 7 },
41 * { 'name': 'metric four', 'data1': 2, 'data2': 14, 'data3': 6, 'data4': 1, 'data5': 23 },
42 * { 'name': 'metric five', 'data1': 27, 'data2': 38, 'data3': 36, 'data4': 13, 'data5': 33 }
46 * Ext.create('Ext.chart.Chart', {
47 * renderTo: Ext.getBody(),
62 * fields: ['data1', 'data2', 'data3', 'data4', 'data5'],
63 * title: 'Sample Values',
73 * adjustMinimumByMajorUnit: 0
79 * title: 'Sample Metrics',
93 * yField: ['data1', 'data2', 'data3', 'data4', 'data5'],
100 Ext.define('Ext.chart.Legend', {
102 /* Begin Definitions */
104 requires: ['Ext.chart.LegendItem'],
106 /* End Definitions */
109 * @cfg {Boolean} visible
110 * Whether or not the legend should be displayed.
115 * @cfg {String} position
116 * The position of the legend in relation to the chart. One of: "top",
117 * "bottom", "left", "right", or "float". If set to "float", then the legend
118 * box will be positioned at the point denoted by the x and y parameters.
124 * X-position of the legend box. Used directly if position is set to "float", otherwise
125 * it will be calculated dynamically.
131 * Y-position of the legend box. Used directly if position is set to "float", otherwise
132 * it will be calculated dynamically.
137 * @cfg {String} labelFont
138 * Font to be used for the legend labels, eg '12px Helvetica'
140 labelFont: '12px Helvetica, sans-serif',
143 * @cfg {String} boxStroke
144 * Style of the stroke for the legend box
149 * @cfg {String} boxStrokeWidth
150 * Width of the stroke for the legend box
155 * @cfg {String} boxFill
156 * Fill style for the legend box
161 * @cfg {Number} itemSpacing
162 * Amount of space between legend items
167 * @cfg {Number} padding
168 * Amount of padding between the legend box's border and its items
178 * @cfg {Number} boxZIndex
179 * Sets the z-index for the legend. Defaults to 100.
184 * Creates new Legend.
185 * @param {Object} config (optional) Config object.
187 constructor: function(config) {
190 Ext.apply(me, config);
194 * Whether the legend box is oriented vertically, i.e. if it is on the left or right side or floating.
197 me.isVertical = ("left|right|float".indexOf(me.position) !== -1);
199 // cache these here since they may get modified later on
205 * @private Create all the sprites for the legend
211 if (!me.created && me.isDisplayed()) {
214 // Listen for changes to series titles to trigger regeneration of the legend
215 me.chart.series.each(function(series) {
216 series.on('titlechange', function() {
225 * @private Determine whether the legend should be displayed. Looks at the legend's 'visible' config,
226 * and also the 'showInLegend' config for each of the series.
228 isDisplayed: function() {
229 return this.visible && this.chart.series.findIndex('showInLegend', true) !== -1;
233 * @private Create the series markers and labels
235 createItems: function() {
238 surface = chart.surface,
240 padding = me.padding,
241 itemSpacing = me.itemSpacing,
247 vertical = me.isVertical,
253 len = items ? items.length : 0,
254 x, y, spacing, item, bbox, height, width;
256 //remove all legend items
258 for (; i < len; i++) {
264 // Create all the item labels, collecting their dimensions and positioning each one
265 // properly in relation to the previous item
266 chart.series.each(function(series, i) {
267 if (series.showInLegend) {
268 Ext.each([].concat(series.yField), function(field, j) {
269 item = Ext.create('Ext.chart.LegendItem', {
272 surface: chart.surface,
275 bbox = item.getBBox();
277 //always measure from x=0, since not all markers go all the way to the left
279 height = bbox.height;
282 spacing = vertical ? padding + height / 2 : padding;
285 spacing = itemSpacing / (vertical ? 2 : 1);
287 // Set the item's position relative to the legend box
288 item.x = mfloor(vertical ? padding : totalWidth + spacing);
289 item.y = mfloor(vertical ? totalHeight + spacing : padding + height / 2);
291 // Collect cumulative dimensions
292 totalWidth += width + spacing;
293 totalHeight += height + spacing;
294 maxWidth = mmax(maxWidth, width);
295 maxHeight = mmax(maxHeight, height);
302 // Store the collected dimensions for later
303 me.width = mfloor((vertical ? maxWidth : totalWidth) + padding * 2);
304 if (vertical && items.length === 1) {
307 me.height = mfloor((vertical ? totalHeight - spacingOffset * spacing : maxHeight) + (padding * 2));
308 me.itemHeight = maxHeight;
312 * @private Get the bounds for the legend's outer box
314 getBBox: function() {
317 x: Math.round(me.x) - me.boxStrokeWidth / 2,
318 y: Math.round(me.y) - me.boxStrokeWidth / 2,
325 * @private Create the box around the legend items
327 createBox: function() {
332 me.boxSprite.destroy();
335 box = me.boxSprite = me.chart.surface.add(Ext.apply({
337 stroke: me.boxStroke,
338 "stroke-width": me.boxStrokeWidth,
347 * @private Update the position of all the legend's sprites to match its current x/y values
349 updatePosition: function() {
352 legendWidth = me.width,
353 legendHeight = me.height,
354 padding = me.padding,
356 chartBBox = chart.chartBBox,
357 insets = chart.insetPadding,
358 chartWidth = chartBBox.width - (insets * 2),
359 chartHeight = chartBBox.height - (insets * 2),
360 chartX = chartBBox.x + insets,
361 chartY = chartBBox.y + insets,
362 surface = chart.surface,
365 if (me.isDisplayed()) {
366 // Find the position based on the dimensions
367 switch(me.position) {
370 y = mfloor(chartY + chartHeight / 2 - legendHeight / 2);
373 x = mfloor(surface.width - legendWidth) - insets;
374 y = mfloor(chartY + chartHeight / 2 - legendHeight / 2);
377 x = mfloor(chartX + chartWidth / 2 - legendWidth / 2);
381 x = mfloor(chartX + chartWidth / 2 - legendWidth / 2);
382 y = mfloor(surface.height - legendHeight) - insets;
385 x = mfloor(me.origX) + insets;
386 y = mfloor(me.origY) + insets;
391 // Update the position of each item
392 Ext.each(me.items, function(item) {
393 item.updatePosition();
395 // Update the position of the outer box
396 me.boxSprite.setAttributes(me.getBBox(), true);