<!DOCTYPE html>
|
<html>
|
<head>
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
<title>The source code</title>
|
<link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
|
<script type="text/javascript" src="../resources/prettify/prettify.js"></script>
|
<style type="text/css">
|
.highlight { display: block; background-color: #ddd; }
|
</style>
|
<script type="text/javascript">
|
function highlight() {
|
document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
|
}
|
</script>
|
</head>
|
<body onload="prettyPrint(); highlight();">
|
<pre class="prettyprint lang-js"><span id='Ext-chart-Legend'>/**
|
</span> * @class Ext.chart.Legend
|
*
|
* Defines a legend for a chart's series.
|
* The 'chart' member must be set prior to rendering.
|
* The legend class displays a list of legend items each of them related with a
|
* series being rendered. In order to render the legend item of the proper series
|
* the series configuration object must have `showInLegend` set to true.
|
*
|
* The legend configuration object accepts a `position` as parameter.
|
* The `position` parameter can be `left`, `right`
|
* `top` or `bottom`. For example:
|
*
|
* legend: {
|
* position: 'right'
|
* },
|
*
|
* ## Example
|
*
|
* @example
|
* var store = Ext.create('Ext.data.JsonStore', {
|
* fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
|
* data: [
|
* { 'name': 'metric one', 'data1': 10, 'data2': 12, 'data3': 14, 'data4': 8, 'data5': 13 },
|
* { 'name': 'metric two', 'data1': 7, 'data2': 8, 'data3': 16, 'data4': 10, 'data5': 3 },
|
* { 'name': 'metric three', 'data1': 5, 'data2': 2, 'data3': 14, 'data4': 12, 'data5': 7 },
|
* { 'name': 'metric four', 'data1': 2, 'data2': 14, 'data3': 6, 'data4': 1, 'data5': 23 },
|
* { 'name': 'metric five', 'data1': 27, 'data2': 38, 'data3': 36, 'data4': 13, 'data5': 33 }
|
* ]
|
* });
|
*
|
* Ext.create('Ext.chart.Chart', {
|
* renderTo: Ext.getBody(),
|
* width: 500,
|
* height: 300,
|
* animate: true,
|
* store: store,
|
* shadow: true,
|
* theme: 'Category1',
|
* legend: {
|
* position: 'top'
|
* },
|
* axes: [
|
* {
|
* type: 'Numeric',
|
* position: 'left',
|
* fields: ['data1', 'data2', 'data3', 'data4', 'data5'],
|
* title: 'Sample Values',
|
* grid: {
|
* odd: {
|
* opacity: 1,
|
* fill: '#ddd',
|
* stroke: '#bbb',
|
* 'stroke-width': 1
|
* }
|
* },
|
* minimum: 0,
|
* adjustMinimumByMajorUnit: 0
|
* },
|
* {
|
* type: 'Category',
|
* position: 'bottom',
|
* fields: ['name'],
|
* title: 'Sample Metrics',
|
* grid: true,
|
* label: {
|
* rotate: {
|
* degrees: 315
|
* }
|
* }
|
* }
|
* ],
|
* series: [{
|
* type: 'area',
|
* highlight: false,
|
* axis: 'left',
|
* xField: 'name',
|
* yField: ['data1', 'data2', 'data3', 'data4', 'data5'],
|
* style: {
|
* opacity: 0.93
|
* }
|
* }]
|
* });
|
*/
|
Ext.define('Ext.chart.Legend', {
|
|
/* Begin Definitions */
|
|
requires: ['Ext.chart.LegendItem'],
|
|
/* End Definitions */
|
|
<span id='Ext-chart-Legend-cfg-visible'> /**
|
</span> * @cfg {Boolean} visible
|
* Whether or not the legend should be displayed.
|
*/
|
visible: true,
|
|
<span id='Ext-chart-Legend-cfg-update'> /**
|
</span> * @cfg {Boolean} update
|
* If set to true the legend will be refreshed when the chart is.
|
* This is useful to update the legend items if series are
|
* added/removed/updated from the chart. Default is true.
|
*/
|
update: true,
|
|
<span id='Ext-chart-Legend-cfg-position'> /**
|
</span> * @cfg {String} position
|
* The position of the legend in relation to the chart. One of: "top",
|
* "bottom", "left", "right", or "float". If set to "float", then the legend
|
* box will be positioned at the point denoted by the x and y parameters.
|
*/
|
position: 'bottom',
|
|
<span id='Ext-chart-Legend-cfg-x'> /**
|
</span> * @cfg {Number} x
|
* X-position of the legend box. Used directly if position is set to "float", otherwise
|
* it will be calculated dynamically.
|
*/
|
x: 0,
|
|
<span id='Ext-chart-Legend-cfg-y'> /**
|
</span> * @cfg {Number} y
|
* Y-position of the legend box. Used directly if position is set to "float", otherwise
|
* it will be calculated dynamically.
|
*/
|
y: 0,
|
|
<span id='Ext-chart-Legend-cfg-labelColor'> /**
|
</span> * @cfg {String} labelColor
|
* Color to be used for the legend labels, eg '#000'
|
*/
|
labelColor: '#000',
|
|
<span id='Ext-chart-Legend-cfg-labelFont'> /**
|
</span> * @cfg {String} labelFont
|
* Font to be used for the legend labels, eg '12px Helvetica'
|
*/
|
labelFont: '12px Helvetica, sans-serif',
|
|
<span id='Ext-chart-Legend-cfg-boxStroke'> /**
|
</span> * @cfg {String} boxStroke
|
* Style of the stroke for the legend box
|
*/
|
boxStroke: '#000',
|
|
<span id='Ext-chart-Legend-cfg-boxStrokeWidth'> /**
|
</span> * @cfg {String} boxStrokeWidth
|
* Width of the stroke for the legend box
|
*/
|
boxStrokeWidth: 1,
|
|
<span id='Ext-chart-Legend-cfg-boxFill'> /**
|
</span> * @cfg {String} boxFill
|
* Fill style for the legend box
|
*/
|
boxFill: '#FFF',
|
|
<span id='Ext-chart-Legend-cfg-itemSpacing'> /**
|
</span> * @cfg {Number} itemSpacing
|
* Amount of space between legend items
|
*/
|
itemSpacing: 10,
|
|
<span id='Ext-chart-Legend-cfg-padding'> /**
|
</span> * @cfg {Number} padding
|
* Amount of padding between the legend box's border and its items
|
*/
|
padding: 5,
|
|
<span id='Ext-chart-Legend-property-width'> // @private
|
</span> width: 0,
|
<span id='Ext-chart-Legend-property-height'> // @private
|
</span> height: 0,
|
|
<span id='Ext-chart-Legend-cfg-boxZIndex'> /**
|
</span> * @cfg {Number} boxZIndex
|
* Sets the z-index for the legend. Defaults to 100.
|
*/
|
boxZIndex: 100,
|
|
<span id='Ext-chart-Legend-method-constructor'> /**
|
</span> * Creates new Legend.
|
* @param {Object} config (optional) Config object.
|
*/
|
constructor: function(config) {
|
var me = this;
|
if (config) {
|
Ext.apply(me, config);
|
}
|
me.items = [];
|
<span id='Ext-chart-Legend-property-isVertical'> /**
|
</span> * Whether the legend box is oriented vertically, i.e. if it is on the left or right side or floating.
|
* @type {Boolean}
|
*/
|
me.isVertical = ("left|right|float".indexOf(me.position) !== -1);
|
|
// cache these here since they may get modified later on
|
me.origX = me.x;
|
me.origY = me.y;
|
},
|
|
<span id='Ext-chart-Legend-method-create'> /**
|
</span> * @private Create all the sprites for the legend
|
*/
|
create: function() {
|
var me = this,
|
seriesItems = me.chart.series.items,
|
i, ln, series;
|
|
me.createBox();
|
|
if (me.rebuild !== false) {
|
me.createItems();
|
}
|
|
if (!me.created && me.isDisplayed()) {
|
me.created = true;
|
|
// Listen for changes to series titles to trigger regeneration of the legend
|
for (i = 0, ln = seriesItems.length; i < ln; i++) {
|
series = seriesItems[i];
|
series.on('titlechange', me.redraw, me);
|
}
|
}
|
},
|
|
<span id='Ext-chart-Legend-method-redraw'> /**
|
</span> * @private Redraws the Legend
|
*/
|
redraw: function() {
|
var me = this;
|
|
me.create();
|
me.updatePosition();
|
},
|
|
<span id='Ext-chart-Legend-method-isDisplayed'> /**
|
</span> * @private Determine whether the legend should be displayed. Looks at the legend's 'visible' config,
|
* and also the 'showInLegend' config for each of the series.
|
*/
|
isDisplayed: function() {
|
return this.visible && this.chart.series.findIndex('showInLegend', true) !== -1;
|
},
|
|
<span id='Ext-chart-Legend-method-createItems'> /**
|
</span> * @private Create the series markers and labels
|
*/
|
createItems: function() {
|
var me = this,
|
seriesItems = me.chart.series.items,
|
items = me.items,
|
fields, i, li, j, lj, series, item;
|
|
//remove all legend items
|
me.removeItems();
|
|
// Create all the item labels
|
for (i = 0, li = seriesItems.length; i < li; i++) {
|
series = seriesItems[i];
|
|
if (series.showInLegend) {
|
fields = [].concat(series.yField);
|
|
for (j = 0, lj = fields.length; j < lj; j++) {
|
item = me.createLegendItem(series, j);
|
items.push(item);
|
}
|
}
|
}
|
|
me.alignItems();
|
},
|
|
<span id='Ext-chart-Legend-method-removeItems'> /**
|
</span> * @private Removes all legend items.
|
*/
|
removeItems: function() {
|
var me = this,
|
items = me.items,
|
len = items ? items.length : 0,
|
i;
|
|
if (len) {
|
for (i = 0; i < len; i++) {
|
items[i].destroy();
|
}
|
}
|
|
//empty array
|
items.length = [];
|
},
|
|
<span id='Ext-chart-Legend-method-alignItems'> /**
|
</span> * @private
|
* Positions all items within Legend box.
|
*/
|
alignItems: function() {
|
var me = this,
|
padding = me.padding,
|
vertical = me.isVertical,
|
mfloor = Math.floor,
|
dim, maxWidth, maxHeight, totalWidth, totalHeight;
|
|
dim = me.updateItemDimensions();
|
|
maxWidth = dim.maxWidth;
|
maxHeight = dim.maxHeight;
|
totalWidth = dim.totalWidth;
|
totalHeight = dim.totalHeight;
|
|
// Store the collected dimensions for later
|
me.width = mfloor((vertical ? maxWidth : totalWidth) + padding * 2);
|
me.height = mfloor((vertical ? totalHeight : maxHeight) + padding * 2);
|
},
|
|
<span id='Ext-chart-Legend-method-updateItemDimensions'> updateItemDimensions: function() {
|
</span> var me = this,
|
items = me.items,
|
padding = me.padding,
|
itemSpacing = me.itemSpacing,
|
maxWidth = 0,
|
maxHeight = 0,
|
totalWidth = 0,
|
totalHeight = 0,
|
vertical = me.isVertical,
|
mfloor = Math.floor,
|
mmax = Math.max,
|
spacing = 0,
|
i, l, item, bbox, width, height;
|
|
// Collect item dimensions and position each one
|
// properly in relation to the previous item
|
for (i = 0, l = items.length; i < l; i++) {
|
item = items[i];
|
|
bbox = item.getBBox();
|
|
//always measure from x=0, since not all markers go all the way to the left
|
width = bbox.width;
|
height = bbox.height;
|
|
spacing = (i === 0 ? 0 : itemSpacing);
|
|
// Set the item's position relative to the legend box
|
item.x = padding + mfloor(vertical ? 0 : totalWidth + spacing);
|
item.y = padding + mfloor(vertical ? totalHeight + spacing : 0) + height / 2;
|
|
// Collect cumulative dimensions
|
totalWidth += spacing + width;
|
totalHeight += spacing + height;
|
maxWidth = mmax(maxWidth, width);
|
maxHeight = mmax(maxHeight, height);
|
}
|
|
return {
|
totalWidth: totalWidth,
|
totalHeight: totalHeight,
|
maxWidth: maxWidth,
|
maxHeight: maxHeight
|
};
|
},
|
|
<span id='Ext-chart-Legend-method-createLegendItem'> /**
|
</span> * @private Creates single Legend Item
|
*/
|
createLegendItem: function(series, yFieldIndex) {
|
var me = this;
|
|
return new Ext.chart.LegendItem({
|
legend: me,
|
series: series,
|
surface: me.chart.surface,
|
yFieldIndex: yFieldIndex
|
});
|
},
|
|
<span id='Ext-chart-Legend-method-getBBox'> /**
|
</span> * @private Get the bounds for the legend's outer box
|
*/
|
getBBox: function() {
|
var me = this;
|
return {
|
x: Math.round(me.x) - me.boxStrokeWidth / 2,
|
y: Math.round(me.y) - me.boxStrokeWidth / 2,
|
width: me.width + me.boxStrokeWidth,
|
height: me.height + me.boxStrokeWidth
|
};
|
},
|
|
<span id='Ext-chart-Legend-method-createBox'> /**
|
</span> * @private Create the box around the legend items
|
*/
|
createBox: function() {
|
var me = this,
|
box, bbox;
|
|
if (me.boxSprite) {
|
me.boxSprite.destroy();
|
}
|
|
bbox = me.getBBox();
|
//if some of the dimensions are NaN this means that we
|
//cannot set a specific width/height for the legend
|
//container. One possibility for this is that there are
|
//actually no items to show in the legend, and the legend
|
//should be hidden.
|
if (isNaN(bbox.width) || isNaN(bbox.height)) {
|
me.boxSprite = false;
|
return;
|
}
|
|
box = me.boxSprite = me.chart.surface.add(Ext.apply({
|
type: 'rect',
|
stroke: me.boxStroke,
|
"stroke-width": me.boxStrokeWidth,
|
fill: me.boxFill,
|
zIndex: me.boxZIndex
|
}, bbox));
|
|
box.redraw();
|
},
|
|
<span id='Ext-chart-Legend-method-calcPosition'> /**
|
</span> * @private Calculates Legend position with respect to other Chart elements.
|
*/
|
calcPosition: function() {
|
var me = this,
|
x, y,
|
legendWidth = me.width,
|
legendHeight = me.height,
|
chart = me.chart,
|
chartBBox = chart.chartBBox,
|
insets = chart.insetPadding,
|
chartWidth = chartBBox.width - (insets * 2),
|
chartHeight = chartBBox.height - (insets * 2),
|
chartX = chartBBox.x + insets,
|
chartY = chartBBox.y + insets,
|
surface = chart.surface,
|
mfloor = Math.floor;
|
|
// Find the position based on the dimensions
|
switch(me.position) {
|
case "left":
|
x = insets;
|
y = mfloor(chartY + chartHeight / 2 - legendHeight / 2);
|
break;
|
case "right":
|
x = mfloor(surface.width - legendWidth) - insets;
|
y = mfloor(chartY + chartHeight / 2 - legendHeight / 2);
|
break;
|
case "top":
|
x = mfloor(chartX + chartWidth / 2 - legendWidth / 2);
|
y = insets;
|
break;
|
case "bottom":
|
x = mfloor(chartX + chartWidth / 2 - legendWidth / 2);
|
y = mfloor(surface.height - legendHeight) - insets;
|
break;
|
default:
|
x = mfloor(me.origX) + insets;
|
y = mfloor(me.origY) + insets;
|
}
|
|
return { x: x, y: y };
|
},
|
|
<span id='Ext-chart-Legend-method-updatePosition'> /**
|
</span> * @private Update the position of all the legend's sprites to match its current x/y values
|
*/
|
updatePosition: function() {
|
var me = this,
|
items = me.items,
|
pos, i, l, bbox;
|
|
if (me.isDisplayed()) {
|
// Find the position based on the dimensions
|
pos = me.calcPosition();
|
|
me.x = pos.x;
|
me.y = pos.y;
|
|
// Update the position of each item
|
for (i = 0, l = items.length; i < l; i++) {
|
items[i].updatePosition();
|
}
|
|
bbox = me.getBBox();
|
|
//if some of the dimensions are NaN this means that we
|
//cannot set a specific width/height for the legend
|
//container. One possibility for this is that there are
|
//actually no items to show in the legend, and the legend
|
//should be hidden.
|
if (isNaN(bbox.width) || isNaN(bbox.height)) {
|
if (me.boxSprite) {
|
me.boxSprite.hide(true);
|
}
|
}
|
else {
|
if (!me.boxSprite) {
|
me.createBox();
|
}
|
|
// Update the position of the outer box
|
me.boxSprite.setAttributes(bbox, true);
|
me.boxSprite.show(true);
|
}
|
}
|
},
|
|
<span id='Ext-chart-Legend-method-toggle'> /** toggle
|
</span> * @param {Boolean} show Whether to show or hide the legend.
|
*
|
*/
|
toggle: function(show) {
|
var me = this,
|
i = 0,
|
items = me.items,
|
len = items.length;
|
|
if (me.boxSprite) {
|
if (show) {
|
me.boxSprite.show(true);
|
} else {
|
me.boxSprite.hide(true);
|
}
|
}
|
|
for (; i < len; ++i) {
|
if (show) {
|
items[i].show(true);
|
} else {
|
items[i].hide(true);
|
}
|
}
|
|
me.visible = show;
|
}
|
});
|
</pre>
|
</body>
|
</html>
|