/**
* @class Ext.chart.series.Pie
* @extends Ext.chart.series.Series
*
* Creates a Pie Chart. A Pie Chart is a useful visualization technique to display quantitative information for different
* categories that also have a meaning as a whole.
* As with all other series, the Pie Series must be appended in the *series* Chart array configuration. See the Chart
* documentation for more information. A typical configuration object for the pie series could be:
*
series: [{
type: 'pie',
field: 'data1',
showInLegend: true,
highlight: {
segment: {
margin: 20
}
},
label: {
field: 'name',
display: 'rotate',
contrast: true,
font: '18px "Lucida Grande"'
}
}]
*
* In this configuration we set `pie` as the type for the series, set an object with specific style properties for highlighting options
* (triggered when hovering elements). We also set true to `showInLegend` so all the pie slices can be represented by a legend item.
* We set `data1` as the value of the field to determine the angle span for each pie slice. We also set a label configuration object
* where we set the field name of the store field to be renderer as text for the label. The labels will also be displayed rotated.
* We set `contrast` to `true` to flip the color of the label if it is to similar to the background color. Finally, we set the font family
* and size through the `font` parameter.
*
* @xtype pie
*
*/
Ext.define('Ext.chart.series.Pie', {
/* Begin Definitions */
extend: 'Ext.chart.series.Series',
requires: ['Ext.fx.Anim'],
/* End Definitions */
type: "pie",
rad: Math.PI / 180,
/**
* @cfg {Number}
* The duration for the pie slice highlight effect.
*/
highlightDuration: 150,
/**
* @cfg {String}
* The store record field name to be used for the pie angles.
* The values bound to this field name must be positive real numbers.
* This parameter is required.
*/
angleField: false,
/**
* @cfg {String}
* The store record field name to be used for the pie slice lengths.
* The values bound to this field name must be positive real numbers.
* This parameter is optional.
*/
lengthField: false,
/**
* @cfg {Boolean|Number}
* Whether to set the pie chart as donut chart.
* Default's false. Can be set to a particular percentage to set the radius
* of the donut chart.
*/
donut: false,
/**
* @cfg {Boolean}
* Whether to add the pie chart elements as legend items. Default's false.
*/
showInLegend: false,
/**
* @cfg {Array} colorSet
* An array of color values which will be used, in order, as the pie slice fill colors.
*/
/**
* @cfg {Object} style
* An object containing styles for overriding series styles from Theming.
*/
style: {},
constructor: function(config) {
this.callParent(arguments);
var me = this,
chart = me.chart,
surface = chart.surface,
store = chart.store,
shadow = chart.shadow, i, l, cfg;
Ext.applyIf(me, {
highlightCfg: {
segment: {
margin: 20
}
}
});
Ext.apply(me, config, {
shadowAttributes: [{
"stroke-width": 6,
"stroke-opacity": 1,
stroke: 'rgb(200, 200, 200)',
translate: {
x: 1.2,
y: 2
}
},
{
"stroke-width": 4,
"stroke-opacity": 1,
stroke: 'rgb(150, 150, 150)',
translate: {
x: 0.9,
y: 1.5
}
},
{
"stroke-width": 2,
"stroke-opacity": 1,
stroke: 'rgb(100, 100, 100)',
translate: {
x: 0.6,
y: 1
}
}]
});
me.group = surface.getGroup(me.seriesId);
if (shadow) {
for (i = 0, l = me.shadowAttributes.length; i < l; i++) {
me.shadowGroups.push(surface.getGroup(me.seriesId + '-shadows' + i));
}
}
surface.customAttributes.segment = function(opt) {
return me.getSegment(opt);
};
//Add yFields to be used in Legend.js
if (me.label.field && !me.yField) {
me.yField = [];
store.each(function(rec) {
me.yField.push(rec.get(me.label.field));
});
}
},
// @private returns an object with properties for a PieSlice.
getSegment: function(opt) {
var me = this,
rad = me.rad,
cos = Math.cos,
sin = Math.sin,
abs = Math.abs,
x = me.centerX,
y = me.centerY,
x1 = 0, x2 = 0, x3 = 0, x4 = 0,
y1 = 0, y2 = 0, y3 = 0, y4 = 0,
delta = 1e-2,
r = opt.endRho - opt.startRho,
startAngle = opt.startAngle,
endAngle = opt.endAngle,
midAngle = (startAngle + endAngle) / 2 * rad,
margin = opt.margin || 0,
flag = abs(endAngle - startAngle) > 180,
a1 = Math.min(startAngle, endAngle) * rad,
a2 = Math.max(startAngle, endAngle) * rad,
singleSlice = false;
x += margin * cos(midAngle);
y += margin * sin(midAngle);
x1 = x + opt.startRho * cos(a1);
y1 = y + opt.startRho * sin(a1);
x2 = x + opt.endRho * cos(a1);
y2 = y + opt.endRho * sin(a1);
x3 = x + opt.startRho * cos(a2);
y3 = y + opt.startRho * sin(a2);
x4 = x + opt.endRho * cos(a2);
y4 = y + opt.endRho * sin(a2);
if (abs(x1 - x3) <= delta && abs(y1 - y3) <= delta) {
singleSlice = true;
}
//Solves mysterious clipping bug with IE
if (singleSlice) {
return {
path: [
["M", x1, y1],
["L", x2, y2],
["A", opt.endRho, opt.endRho, 0, +flag, 1, x4, y4],
["Z"]]
};
} else {
return {
path: [
["M", x1, y1],
["L", x2, y2],
["A", opt.endRho, opt.endRho, 0, +flag, 1, x4, y4],
["L", x3, y3],
["A", opt.startRho, opt.startRho, 0, +flag, 0, x1, y1],
["Z"]]
};
}
},
// @private utility function to calculate the middle point of a pie slice.
calcMiddle: function(item) {
var me = this,
rad = me.rad,
slice = item.slice,
x = me.centerX,
y = me.centerY,
startAngle = slice.startAngle,
endAngle = slice.endAngle,
radius = Math.max(('rho' in slice) ? slice.rho: me.radius, me.label.minMargin),
donut = +me.donut,
a1 = Math.min(startAngle, endAngle) * rad,
a2 = Math.max(startAngle, endAngle) * rad,
midAngle = -(a1 + (a2 - a1) / 2),
xm = x + (item.endRho + item.startRho) / 2 * Math.cos(midAngle),
ym = y - (item.endRho + item.startRho) / 2 * Math.sin(midAngle);
item.middle = {
x: xm,
y: ym
};
},
/**
* Draws the series for the current chart.
*/
drawSeries: function() {
var me = this,
store = me.chart.substore || me.chart.store,
group = me.group,
animate = me.chart.animate,
field = me.angleField || me.field || me.xField,
lenField = [].concat(me.lengthField),
totalLenField = 0,
colors = me.colorSet,
chart = me.chart,
surface = chart.surface,
chartBBox = chart.chartBBox,
enableShadows = chart.shadow,
shadowGroups = me.shadowGroups,
shadowAttributes = me.shadowAttributes,
lnsh = shadowGroups.length,
rad = me.rad,
layers = lenField.length,
rhoAcum = 0,
donut = +me.donut,
layerTotals = [],
values = {},
fieldLength,
items = [],
passed = false,
totalField = 0,
maxLenField = 0,
cut = 9,
defcut = true,
angle = 0,
seriesStyle = me.seriesStyle,
seriesLabelStyle = me.seriesLabelStyle,
colorArrayStyle = me.colorArrayStyle,
colorArrayLength = colorArrayStyle && colorArrayStyle.length || 0,
rendererAttributes,
shadowGroup,
shadowAttr,
shadows,
shadow,
shindex,
centerX,
centerY,
deltaRho,
first = 0,
slice,
slices,
sprite,
value,
item,
lenValue,
ln,
record,
i,
j,
startAngle,
endAngle,
middleAngle,
sliceLength,
path,
p,
spriteOptions;
Ext.apply(seriesStyle, me.style || {});
//override theme colors
if (me.colorSet) {
colorArrayStyle = me.colorSet;
colorArrayLength = colorArrayStyle.length;
}
me.unHighlightItem();
me.cleanHighlights();
centerX = me.centerX = chartBBox.x + (chartBBox.width / 2);
centerY = me.centerY = chartBBox.y + (chartBBox.height / 2);
me.radius = Math.min(centerX - chartBBox.x, centerY - chartBBox.y);
me.slices = slices = [];
me.items = items = [];
store.each(function(record, i) {
if (this.__excludes && this.__excludes[i]) {
//hidden series
return;
}
totalField += +record.get(field);
if (lenField[0]) {
for (j = 0, totalLenField = 0; j < layers; j++) {
totalLenField += +record.get(lenField[j]);
}
layerTotals[i] = totalLenField;
maxLenField = Math.max(maxLenField, totalLenField);
}
}, this);
store.each(function(record, i) {
if (this.__excludes && this.__excludes[i]) {
//hidden series
return;
}
value = record.get(field);
middleAngle = angle - 360 * value / totalField / 2;
// First slice
if (!i || first == 0) {
angle = 360 - middleAngle;
me.firstAngle = angle;
middleAngle = angle - 360 * value / totalField / 2;
}
endAngle = angle - 360 * value / totalField;
slice = {
series: me,
value: value,
startAngle: angle,
endAngle: endAngle,
storeItem: record
};
if (lenField[0]) {
lenValue = layerTotals[i];
slice.rho = me.radius * (lenValue / maxLenField);
} else {
slice.rho = me.radius;
}
slices[i] = slice;
if((slice.startAngle % 360) == (slice.endAngle % 360)) {
slice.startAngle -= 0.0001;
}
angle = endAngle;
first++;
}, me);
//do all shadows first.
if (enableShadows) {
for (i = 0, ln = slices.length; i < ln; i++) {
if (this.__excludes && this.__excludes[i]) {
//hidden series
continue;
}
slice = slices[i];
slice.shadowAttrs = [];
for (j = 0, rhoAcum = 0, shadows = []; j < layers; j++) {
sprite = group.getAt(i * layers + j);
deltaRho = lenField[j] ? store.getAt(i).get(lenField[j]) / layerTotals[i] * slice.rho: slice.rho;
//set pie slice properties
rendererAttributes = {
segment: {
startAngle: slice.startAngle,
endAngle: slice.endAngle,
margin: 0,
rho: slice.rho,
startRho: rhoAcum + (deltaRho * donut / 100),
endRho: rhoAcum + deltaRho
}
};
//create shadows
for (shindex = 0, shadows = []; shindex < lnsh; shindex++) {
shadowAttr = shadowAttributes[shindex];
shadow = shadowGroups[shindex].getAt(i);
if (!shadow) {
shadow = chart.surface.add(Ext.apply({},
{
type: 'path',
group: shadowGroups[shindex],
strokeLinejoin: "round"
},
rendererAttributes, shadowAttr));
}
if (animate) {
rendererAttributes = me.renderer(shadow, store.getAt(i), Ext.apply({},
rendererAttributes, shadowAttr), i, store);
me.onAnimate(shadow, {
to: rendererAttributes
});
} else {
rendererAttributes = me.renderer(shadow, store.getAt(i), Ext.apply(shadowAttr, {
hidden: false
}), i, store);
shadow.setAttributes(rendererAttributes, true);
}
shadows.push(shadow);
}
slice.shadowAttrs[j] = shadows;
}
}
}
//do pie slices after.
for (i = 0, ln = slices.length; i < ln; i++) {
if (this.__excludes && this.__excludes[i]) {
//hidden series
continue;
}
slice = slices[i];
for (j = 0, rhoAcum = 0; j < layers; j++) {
sprite = group.getAt(i * layers + j);
deltaRho = lenField[j] ? store.getAt(i).get(lenField[j]) / layerTotals[i] * slice.rho: slice.rho;
//set pie slice properties
rendererAttributes = Ext.apply({
segment: {
startAngle: slice.startAngle,
endAngle: slice.endAngle,
margin: 0,
rho: slice.rho,
startRho: rhoAcum + (deltaRho * donut / 100),
endRho: rhoAcum + deltaRho
}
}, Ext.apply(seriesStyle, colorArrayStyle && { fill: colorArrayStyle[(layers > 1? j : i) % colorArrayLength] } || {}));
item = Ext.apply({},
rendererAttributes.segment, {
slice: slice,
series: me,
storeItem: slice.storeItem,
index: i
});
me.calcMiddle(item);
if (enableShadows) {
item.shadows = slice.shadowAttrs[j];
}
items[i] = item;
// Create a new sprite if needed (no height)
if (!sprite) {
spriteOptions = Ext.apply({
type: "path",
group: group,
middle: item.middle
}, Ext.apply(seriesStyle, colorArrayStyle && { fill: colorArrayStyle[(layers > 1? j : i) % colorArrayLength] } || {}));
sprite = surface.add(Ext.apply(spriteOptions, rendererAttributes));
}
slice.sprite = slice.sprite || [];
item.sprite = sprite;
slice.sprite.push(sprite);
slice.point = [item.middle.x, item.middle.y];
if (animate) {
rendererAttributes = me.renderer(sprite, store.getAt(i), rendererAttributes, i, store);
sprite._to = rendererAttributes;
sprite._animating = true;
me.animation = me.onAnimate(sprite, {
to: rendererAttributes
});
me.animation.on('afteranimate', (function(s) {
return function() {
s._animating = false;
};
})(sprite));
} else {
rendererAttributes = me.renderer(sprite, store.getAt(i), Ext.apply(rendererAttributes, {
hidden: false
}), i, store);
sprite.setAttributes(rendererAttributes, true);
}
rhoAcum += deltaRho;
}
}
// Hide unused bars
ln = group.getCount();
for (i = 0; i < ln; i++) {
if (!slices[(i / layers) >> 0] && group.getAt(i)) {
group.getAt(i).hide(true);
}
}
if (enableShadows) {
for (shindex = 0; shindex < lnsh; shindex++) {
shadowGroup = shadowGroups[shindex];
ln = shadowGroup.getCount();
for (j = i; j < ln; j++) {
shadowGroup.getAt(j).hide(true);
}
}
}
me.renderLabels();
me.renderCallouts();
},
// @private callback for when creating a label sprite.
onCreateLabel: function(storeItem, item, i, display) {
var me = this,
group = me.labelsGroup,
config = me.label,
centerX = me.centerX,
centerY = me.centerY,
middle = item.middle,
endLabelStyle = Ext.apply(me.seriesLabelStyle || {}, config || {});
return me.chart.surface.add(Ext.apply({
'type': 'text',
'text-anchor': 'middle',
'group': group,
'x': middle.x,
'y': middle.y
}, endLabelStyle));
},
// @private callback for when placing a label sprite.
onPlaceLabel: function(label, storeItem, item, i, display, animate, index) {
var me = this,
chart = me.chart,
resizing = chart.resizing,
config = me.label,
format = config.renderer,
field = [].concat(config.field),
centerX = me.centerX,
centerY = me.centerY,
middle = item.middle,
opt = {
x: middle.x,
y: middle.y
},
x = middle.x - centerX,
y = middle.y - centerY,
rho = 1,
theta = Math.atan2(y, x || 1),
dg = theta * 180 / Math.PI,
prevDg;
function fixAngle(a) {
if (a < 0) a += 360;
return a % 360;
}
label.setAttributes({
text: format(storeItem.get(field[index])),
hidden: true
},
true);
switch (display) {
case 'outside':
rho = Math.sqrt(x * x + y * y) * 2;
//update positions
opt.x = rho * Math.cos(theta) + centerX;
opt.y = rho * Math.sin(theta) + centerY;
break;
case 'rotate':
dg = fixAngle(dg);
dg = (dg > 90 && dg < 270) ? dg + 180: dg;
prevDg = label.attr.rotation.degrees;
if (prevDg != null && Math.abs(prevDg - dg) > 180) {
if (dg > prevDg) {
dg -= 360;
} else {
dg += 360;
}
dg = dg % 360;
} else {
dg = fixAngle(dg);
}
//update rotation angle
opt.rotate = {
degrees: dg,
x: opt.x,
y: opt.y
};
break;
default:
break;
}
if (animate && !resizing && (display != 'rotate' || prevDg != null)) {
label.show(true);
me.onAnimate(label, {
to: opt
});
} else {
label.setAttributes(opt, true);
if (resizing && me.animation) {
me.animation.on('afteranimate',
function() {
label.show(true);
});
} else {
label.show(true);
}
}
},
// @private callback for when placing a callout sprite.
onPlaceCallout: function(callout, storeItem, item, i, display, animate, index) {
var me = this,
chart = me.chart,
resizing = chart.resizing,
config = me.callouts,
centerX = me.centerX,
centerY = me.centerY,
middle = item.middle,
opt = {
x: middle.x,
y: middle.y
},
x = middle.x - centerX,
y = middle.y - centerY,
rho = 1,
rhoCenter,
theta = Math.atan2(y, x || 1),
bbox = callout.label.getBBox(),
offsetFromViz = 20,
offsetToSide = 10,
offsetBox = 10,
p;
//should be able to config this.
rho = item.endRho + offsetFromViz;
rhoCenter = (item.endRho + item.startRho) / 2 + (item.endRho - item.startRho) / 3;
//update positions
opt.x = rho * Math.cos(theta) + centerX;
opt.y = rho * Math.sin(theta) + centerY;
x = rhoCenter * Math.cos(theta);
y = rhoCenter * Math.sin(theta);
if (chart.animate) {
//set the line from the middle of the pie to the box.
me.onAnimate(callout.lines, {
to: {
path: ["M", x + centerX, y + centerY, "L", opt.x, opt.y, "Z", "M", opt.x, opt.y, "l", x > 0 ? offsetToSide: -offsetToSide, 0, "z"]
}
});
//set box position
me.onAnimate(callout.box, {
to: {
x: opt.x + (x > 0 ? offsetToSide: -(offsetToSide + bbox.width + 2 * offsetBox)),
y: opt.y + (y > 0 ? ( - bbox.height - offsetBox / 2) : ( - bbox.height - offsetBox / 2)),
width: bbox.width + 2 * offsetBox,
height: bbox.height + 2 * offsetBox
}
});
//set text position
me.onAnimate(callout.label, {
to: {
x: opt.x + (x > 0 ? (offsetToSide + offsetBox) : -(offsetToSide + bbox.width + offsetBox)),
y: opt.y + (y > 0 ? -bbox.height / 4: -bbox.height / 4)
}
});
} else {
//set the line from the middle of the pie to the box.
callout.lines.setAttributes({
path: ["M", x + centerX, y + centerY, "L", opt.x, opt.y, "Z", "M", opt.x, opt.y, "l", x > 0 ? offsetToSide: -offsetToSide, 0, "z"]
},
true);
//set box position
callout.box.setAttributes({
x: opt.x + (x > 0 ? offsetToSide: -(offsetToSide + bbox.width + 2 * offsetBox)),
y: opt.y + (y > 0 ? ( - bbox.height - offsetBox / 2) : ( - bbox.height - offsetBox / 2)),
width: bbox.width + 2 * offsetBox,
height: bbox.height + 2 * offsetBox
},
true);
//set text position
callout.label.setAttributes({
x: opt.x + (x > 0 ? (offsetToSide + offsetBox) : -(offsetToSide + bbox.width + offsetBox)),
y: opt.y + (y > 0 ? -bbox.height / 4: -bbox.height / 4)
},
true);
}
for (p in callout) {
callout[p].show(true);
}
},
// @private handles sprite animation for the series.
onAnimate: function(sprite, attr) {
sprite.show();
return this.callParent(arguments);
},
/**
* For a given x/y point relative to the Surface, find a corresponding item from this
* series, if any.
*
* @param x {Number} The left pointer coordinate.
* @param y {Number} The top pointer coordinate.
* @return {Object} An object with the item found or null instead.
*/
getItemForPoint: function(x, y) {
var me = this,
cx = me.centerX,
cy = me.centerY,
abs = Math.abs,
dx = abs(x - cx),
dy = abs(y - cy),
items = me.items,
item,
i = items && items.length,
angle,
startAngle,
endAngle,
rho = Math.sqrt(dx * dx + dy * dy);
// Make sure we're within the pie circle area
if (i && rho <= me.radius) {
angle = Math.atan2(y - cy, x - cx) / me.rad + 360;
// normalize to the same range of angles created by drawSeries
if (angle > me.firstAngle) {
angle -= 360;
}
while (i--) {
item = items[i];
if (item) {
startAngle = item.startAngle;
endAngle = item.endAngle;
if (angle <= startAngle && angle > endAngle && rho >= item.startRho && rho <= item.endRho) {
return item;
}
}
}
}
return null;
},
// @private hides all elements in the series.
hideAll: function() {
var i, l, shadow, shadows, sh, lsh, sprite;
if (!isNaN(this._index)) {
this.__excludes = this.__excludes || [];
this.__excludes[this._index] = true;
sprite = this.slices[this._index].sprite;
for (sh = 0, lsh = sprite.length; sh < lsh; sh++) {
sprite[sh].setAttributes({
hidden: true
}, true);
}
if (this.slices[this._index].shadowAttrs) {
for (i = 0, shadows = this.slices[this._index].shadowAttrs, l = shadows.length; i < l; i++) {
shadow = shadows[i];
for (sh = 0, lsh = shadow.length; sh < lsh; sh++) {
shadow[sh].setAttributes({
hidden: true
}, true);
}
}
}
this.drawSeries();
}
},
// @private shows all elements in the series.
showAll: function() {
if (!isNaN(this._index)) {
this.__excludes[this._index] = false;
this.drawSeries();
}
},
/**
* Highlight the specified item. If no item is provided the whole series will be highlighted.
* @param item {Object} Info about the item; same format as returned by #getItemForPoint
*/
highlightItem: function(item) {
var me = this,
rad = me.rad;
item = item || this.items[this._index];
if (!item || item.sprite && item.sprite._animating) {
return;
}
me.callParent([item]);
if (!me.highlight) {
return;
}
if ('segment' in me.highlightCfg) {
var highlightSegment = me.highlightCfg.segment,
animate = me.chart.animate,
attrs,
i, shadows, shadow, ln, to, itemHighlightSegment, prop;
//animate labels
if (me.labelsGroup) {
var group = me.labelsGroup,
display = me.label.display,
label = group.getAt(item.index),
middle = (item.startAngle + item.endAngle) / 2 * rad,
r = highlightSegment.margin || 0,
x = r * Math.cos(middle),
y = r * Math.sin(middle);
if (animate) {
label._anim = new Ext.fx.Anim({
to: {
translate: {
x: x,
y: y
}
},
target: label,
duration: me.highlightDuration
});
}
else {
label.setAttributes({
translate: {
x: x,
y: y
}
}, true);
}
}
//animate shadows
if (me.chart.shadow && item.shadows) {
i = 0;
shadows = item.shadows;
ln = shadows.length;
for (; i < ln; i++) {
shadow = shadows[i];
to = {};
itemHighlightSegment = item.sprite._from.segment;
for (prop in itemHighlightSegment) {
if (! (prop in highlightSegment)) {
to[prop] = itemHighlightSegment[prop];
}
}
attrs = {
segment: Ext.apply(to, me.highlightCfg.segment)
};
if (animate) {
shadow._anim = new Ext.fx.Anim({
target: shadow,
to: attrs,
duration: me.highlightDuration
});
}
else {
shadow.setAttributes(attrs, true);
}
}
}
}
},
/**
* un-highlights the specified item. If no item is provided it will un-highlight the entire series.
* @param item {Object} Info about the item; same format as returned by #getItemForPoint
*/
unHighlightItem: function() {
var me = this;
if (!me.highlight) {
return;
}
if (('segment' in me.highlightCfg) && me.items) {
var items = me.items,
animate = me.chart.animate,
shadowsEnabled = !!me.chart.shadow,
group = me.labelsGroup,
len = items.length,
i = 0,
j = 0,
display = me.label.display,
shadowLen, p, to, ihs,
hs,
sprite,
shadows,
shadow,
item,
label,
attrs;
for (; i < len; i++) {
item = items[i];
if (!item) {
continue;
}
sprite = item.sprite;
if (sprite && sprite._highlighted) {
//animate labels
if (group) {
label = group.getAt(item.index);
attrs = {
to: Ext.apply({
translate: {
x: 0,
y: 0
}
},
display == 'rotate' ? {
rotate: {
x: label.attr.x,
y: label.attr.y,
degrees: label.attr.rotation.degrees
}
}: {})
};
if (animate) {
label._anim.paused = true;
label._anim = new Ext.fx.Anim({
target: label,
to: attrs.to,
duration: me.highlightDuration
});
}
else {
label.setAttributes(attrs.to, true);
}
}
if (shadowsEnabled) {
shadows = item.shadows;
shadowLen = shadows.length;
for (; j < shadowLen; j++) {
to = {};
ihs = item.sprite._to.segment;
hs = item.sprite._from.segment;
Ext.apply(to, hs);
for (p in ihs) {
if (! (p in hs)) {
to[p] = ihs[p];
}
}
shadow = shadows[j];
if (animate) {
shadow._anim.paused = true;
shadow._anim = new Ext.fx.Anim({
target: shadow,
to: {
segment: to
},
duration: me.highlightDuration
});
}
else {
shadow.setAttributes({ segment: to }, true);
}
}
}
}
}
}
me.callParent(arguments);
},
/**
* Returns the color of the series (to be displayed as color for the series legend item).
* @param item {Object} Info about the item; same format as returned by #getItemForPoint
*/
getLegendColor: function(index) {
var me = this;
return me.colorArrayStyle[index % me.colorArrayStyle.length];
}
});