blob: 2b80d992a1a0507f877dfce53b3f7309d598b58f [file] [log] [blame]
/**
* echarts图表类:饼图
*
* @desc echarts基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据统计图表。
* @author Kener (@Kener-林峰, linzhifeng@baidu.com)
*
*/
define(function(require) {
/**
* 构造函数
* @param {Object} messageCenter echart消息中心
* @param {ZRender} zr zrender实例
* @param {Object} series 数据
* @param {Object} component 组件
*/
function Pie(ecConfig, messageCenter, zr, option, component){
// 基类装饰
var ComponentBase = require('../component/base');
ComponentBase.call(this, ecConfig, zr);
// 可计算特性装饰
var CalculableBase = require('./calculableBase');
CalculableBase.call(this, zr, option);
var ecData = require('../util/ecData');
var zrMath = require('zrender/tool/math');
var zrUtil = require('zrender/tool/util');
var zrColor = require('zrender/tool/color');
var self = this;
self.type = ecConfig.CHART_TYPE_PIE;
var series; // 共享数据源,不要修改跟自己无关的项
var _zlevelBase = self.getZlevelBase();
var _selectedMode;
var _selected = {};
function _buildShape() {
var legend = component.legend;
self.selectedMap = {};
_selected = {};
var center;
var radius;
var pieCase; // 饼图箱子
_selectedMode = false;
var serieName;
for (var i = 0, l = series.length; i < l; i++) {
if (series[i].type == ecConfig.CHART_TYPE_PIE) {
series[i] = self.reformOption(series[i]);
serieName = series[i].name || '';
// 系列图例开关
self.selectedMap[serieName] =
legend ? legend.isSelected(serieName) : true;
if (!self.selectedMap[serieName]) {
continue;
}
center = self.parseCenter(zr, series[i].center);
radius = self.parseRadius(zr, series[i].radius);
_selectedMode = _selectedMode || series[i].selectedMode;
_selected[i] = [];
if (self.deepQuery([series[i], option], 'calculable')) {
pieCase = {
shape : radius[0] <= 10 ? 'circle' : 'ring',
zlevel : _zlevelBase,
hoverable : false,
style : {
x : center[0], // 圆心横坐标
y : center[1], // 圆心纵坐标
// 圆环内外半径
r0 : radius[0] <= 10 ? 0 : radius[0] - 10,
r : radius[1] + 10,
brushType : 'stroke',
lineWidth: 1,
strokeColor : series[i].calculableHolderColor
|| ecConfig.calculableHolderColor
}
};
ecData.pack(pieCase, series[i], i, undefined, -1);
self.setCalculable(pieCase);
self.shapeList.push(pieCase);
}
_buildSinglePie(i);
self.buildMark(
series[i],
i,
component
);
}
}
for (var i = 0, l = self.shapeList.length; i < l; i++) {
self.shapeList[i].id = zr.newShapeId(self.type);
zr.addShape(self.shapeList[i]);
}
}
/**
* 构建单个饼图
*
* @param {number} seriesIndex 系列索引
*/
function _buildSinglePie(seriesIndex) {
var serie = series[seriesIndex];
var data = serie.data;
var legend = component.legend;
var itemName;
var totalSelected = 0; // 迭代累计选中且非0个数
var totalSelectedValue0 = 0; // 迭代累计选中0只个数
var totalValue = 0; // 迭代累计
var maxValue = Number.NEGATIVE_INFINITY;
// 计算需要显示的个数和总值
for (var i = 0, l = data.length; i < l; i++) {
itemName = data[i].name;
if (legend){
self.selectedMap[itemName] = legend.isSelected(itemName);
} else {
self.selectedMap[itemName] = true;
}
if (self.selectedMap[itemName] && !isNaN(data[i].value)) {
if (+data[i].value !== 0) {
totalSelected++;
}
else {
totalSelectedValue0++;
}
totalValue += +data[i].value;
maxValue = Math.max(maxValue, +data[i].value);
}
}
var percent = 100;
var lastPercent; // 相邻细角度优化
var lastAddRadius = 0;
var clockWise = serie.clockWise;
var startAngle = serie.startAngle.toFixed(2) - 0;
var endAngle;
var minAngle = serie.minAngle || 0.01; // #bugfixed
var totalAngle = 360 - (minAngle * totalSelected)
- 0.01 * totalSelectedValue0;
var defaultColor;
var roseType = serie.roseType;
var radius;
var r0; // 扇形内半径
var r1; // 扇形外半径
for (var i = 0, l = data.length; i < l; i++){
itemName = data[i].name;
if (!self.selectedMap[itemName] || isNaN(data[i].value)) {
continue;
}
// 默认颜色策略
if (legend) {
// 有图例则从图例中获取颜色定义
defaultColor = legend.getColor(itemName);
}
else {
// 全局颜色定义
defaultColor = zr.getColor(i);
}
lastPercent = percent;
percent = data[i].value / totalValue;
if (roseType != 'area') {
endAngle = clockWise
? (startAngle - percent * totalAngle - (percent !== 0 ? minAngle : 0.01))
: (percent * totalAngle + startAngle + (percent !== 0 ? minAngle : 0.01));
}
else {
endAngle = clockWise
? (startAngle - 360 / l)
: (360 / l + startAngle);
}
endAngle = endAngle.toFixed(2) - 0;
percent = (percent * 100).toFixed(2);
radius = self.parseRadius(zr, serie.radius);
r0 = +radius[0];
r1 = +radius[1];
if (roseType == 'radius') {
r1 = data[i].value / maxValue * (r1 - r0) * 0.8
+ (r1 - r0) * 0.2
+ r0;
}
else if (roseType == 'area') {
r1 = Math.sqrt(data[i].value / maxValue) * (r1 - r0) + r0;
}
if (clockWise) {
var temp;
temp = startAngle;
startAngle = endAngle;
endAngle = temp;
}
// 当前小角度需要检查前一个是否也是小角度,如果是得调整长度,不能完全避免,但能大大降低覆盖概率
if (i > 0
&& percent < 4 // 约15度
&& lastPercent < 4
&& _needLabel(serie, data[i], false)
&& self.deepQuery(
[data[i], serie], 'itemStyle.normal.label.position'
) != 'center'
) {
// 都小就延长,前小后大就缩短
lastAddRadius += (percent < 4 ? 20 : -20);
}
else {
lastAddRadius = 0;
}
_buildItem(
seriesIndex, i, percent, lastAddRadius, // 相邻最小角度优化
data[i].selected,
r0, r1,
startAngle, endAngle, defaultColor
);
if (!clockWise) {
startAngle = endAngle;
}
}
}
/**
* 构建单个扇形及指标
*/
function _buildItem(
seriesIndex, dataIndex, percent, lastAddRadius,
isSelected,
r0, r1,
startAngle, endAngle, defaultColor
) {
// 扇形
var sector = _getSector(
seriesIndex, dataIndex, percent, isSelected,
r0, r1,
startAngle, endAngle, defaultColor
);
// 图形需要附加的私有数据
ecData.pack(
sector,
series[seriesIndex], seriesIndex,
series[seriesIndex].data[dataIndex], dataIndex,
series[seriesIndex].data[dataIndex].name,
percent
);
sector._lastAddRadius = lastAddRadius;
self.shapeList.push(sector);
// 文本标签,需要显示则会有返回
var label = _getLabel(
seriesIndex, dataIndex, percent, lastAddRadius,
startAngle, endAngle, defaultColor,
false
);
if (label) {
label._dataIndex = dataIndex;
self.shapeList.push(label);
}
// 文本标签视觉引导线,需要显示则会有返回
var labelLine = _getLabelLine(
seriesIndex, dataIndex, lastAddRadius,
r0, r1,
startAngle, endAngle, defaultColor,
false
);
if (labelLine) {
labelLine._dataIndex = dataIndex;
self.shapeList.push(labelLine);
}
}
/**
* 构建扇形
*/
function _getSector(
seriesIndex, dataIndex, percent, isSelected,
r0, r1,
startAngle, endAngle, defaultColor
) {
var serie = series[seriesIndex];
var data = serie.data[dataIndex];
var queryTarget = [data, serie];
var center = self.parseCenter(zr, serie.center);
// 多级控制
var normal = self.deepMerge(
queryTarget,
'itemStyle.normal'
) || {};
var emphasis = self.deepMerge(
queryTarget,
'itemStyle.emphasis'
) || {};
var normalColor = self.getItemStyleColor(normal.color, seriesIndex, dataIndex, data)
|| defaultColor;
var emphasisColor = self.getItemStyleColor(emphasis.color, seriesIndex, dataIndex, data)
|| (typeof normalColor == 'string'
? zrColor.lift(normalColor, -0.2)
: normalColor
);
var sector = {
shape : 'sector', // 扇形
zlevel : _zlevelBase,
clickable : true,
style : {
x : center[0], // 圆心横坐标
y : center[1], // 圆心纵坐标
r0 : r0, // 圆环内半径
r : r1, // 圆环外半径
startAngle : startAngle,
endAngle : endAngle,
brushType : 'both',
color : normalColor,
lineWidth : normal.borderWidth,
strokeColor : normal.borderColor,
lineJoin: 'round'
},
highlightStyle : {
color : emphasisColor,
lineWidth : emphasis.borderWidth,
strokeColor : emphasis.borderColor,
lineJoin: 'round'
},
_seriesIndex : seriesIndex,
_dataIndex : dataIndex
};
if (isSelected) {
var midAngle =
((sector.style.startAngle + sector.style.endAngle) / 2)
.toFixed(2) - 0;
sector.style._hasSelected = true;
sector.style._x = sector.style.x;
sector.style._y = sector.style.y;
var offset = self.query(serie, 'selectedOffset');
sector.style.x += zrMath.cos(midAngle, true) * offset;
sector.style.y -= zrMath.sin(midAngle, true) * offset;
_selected[seriesIndex][dataIndex] = true;
}
else {
_selected[seriesIndex][dataIndex] = false;
}
if (_selectedMode) {
sector.onclick = self.shapeHandler.onclick;
}
if (self.deepQuery([data, serie, option], 'calculable')) {
self.setCalculable(sector);
sector.draggable = true;
}
// “normal下不显示,emphasis显示”添加事件响应
if (_needLabel(serie, data, true) // emphasis下显示文本
|| _needLabelLine(serie, data, true) // emphasis下显示引导线
) {
sector.onmouseover = self.shapeHandler.onmouseover;
}
return sector;
}
/**
* 需要显示则会有返回构建好的shape,否则返回undefined
*/
function _getLabel(
seriesIndex, dataIndex, percent, lastAddRadius,
startAngle, endAngle, defaultColor,
isEmphasis
) {
var serie = series[seriesIndex];
var data = serie.data[dataIndex];
// 特定状态下是否需要显示文本标签
if (!_needLabel(serie, data, isEmphasis)) {
return;
}
var status = isEmphasis ? 'emphasis' : 'normal';
// serie里有默认配置,放心大胆的用!
var itemStyle = zrUtil.merge(
zrUtil.clone(data.itemStyle) || {},
serie.itemStyle,
{
'overwrite' : false,
'recursive' : true
}
);
// label配置
var labelControl = itemStyle[status].label;
var textStyle = labelControl.textStyle || {};
var center = self.parseCenter(zr, serie.center);
var centerX = center[0]; // 圆心横坐标
var centerY = center[1]; // 圆心纵坐标
var x;
var y;
var midAngle = ((endAngle + startAngle) / 2 + 360) % 360; // 中值
var radius = self.parseRadius(zr, serie.radius); // 标签位置半径
var textAlign;
var textBaseline = 'middle';
labelControl.position = labelControl.position
|| itemStyle.normal.label.position;
if (labelControl.position == 'center') {
// center显示
radius = radius[1];
x = centerX;
y = centerY;
textAlign = 'center';
}
else if (labelControl.position == 'inner'){
// 内部显示
radius = (radius[0] + radius[1]) / 2 + lastAddRadius;
x = Math.round(
centerX + radius * zrMath.cos(midAngle, true)
);
y = Math.round(
centerY - radius * zrMath.sin(midAngle, true)
);
defaultColor = '#fff';
textAlign = 'center';
}
else {
// 外部显示,默认 labelControl.position == 'outer')
radius = radius[1]
- (-itemStyle[status].labelLine.length)
//- (-textStyle.fontSize)
+ lastAddRadius;
x = centerX + radius * zrMath.cos(midAngle, true);
y = centerY - radius * zrMath.sin(midAngle, true);
textAlign = (midAngle >= 90 && midAngle <= 270)
? 'right' : 'left';
}
if (labelControl.position != 'center'
&& labelControl.position != 'inner'
) {
x += textAlign == 'left' ? 20 : -20;
}
data.__labelX = x - (textAlign == 'left' ? 5 : -5);
data.__labelY = y;
return {
shape : 'text',
zlevel : _zlevelBase + 1,
hoverable : false,
style : {
x : x,
y : y,
color : textStyle.color || defaultColor,
text : _getLabelText(
seriesIndex, dataIndex, percent, status
),
textAlign : textStyle.align || textAlign,
textBaseline : textStyle.baseline || textBaseline,
textFont : self.getFont(textStyle)
},
highlightStyle : {
brushType : 'fill'
},
_seriesIndex : seriesIndex,
_dataIndex : dataIndex
};
}
/**
* 根据lable.format计算label text
*/
function _getLabelText(seriesIndex, dataIndex, percent, status) {
var serie = series[seriesIndex];
var data = serie.data[dataIndex];
var formatter = self.deepQuery(
[data, serie],
'itemStyle.' + status + '.label.formatter'
);
if (formatter) {
if (typeof formatter == 'function') {
return formatter(
serie.name,
data.name,
data.value,
percent
);
}
else if (typeof formatter == 'string') {
formatter = formatter.replace('{a}','{a0}')
.replace('{b}','{b0}')
.replace('{c}','{c0}')
.replace('{d}','{d0}');
formatter = formatter.replace('{a0}', serie.name)
.replace('{b0}', data.name)
.replace('{c0}', data.value)
.replace('{d0}', percent);
return formatter;
}
}
else {
return data.name;
}
}
/**
* 需要显示则会有返回构建好的shape,否则返回undefined
*/
function _getLabelLine(
seriesIndex, dataIndex, lastAddRadius,
r0, r1,
startAngle, endAngle, defaultColor,
isEmphasis
) {
var serie = series[seriesIndex];
var data = serie.data[dataIndex];
// 特定状态下是否需要显示文本标签
if (_needLabelLine(serie, data, isEmphasis)) {
var status = isEmphasis ? 'emphasis' : 'normal';
// serie里有默认配置,放心大胆的用!
var itemStyle = zrUtil.merge(
zrUtil.clone(data.itemStyle) || {},
serie.itemStyle,
{
'overwrite' : false,
'recursive' : true
}
);
// labelLine配置
var labelLineControl = itemStyle[status].labelLine;
var lineStyle = labelLineControl.lineStyle || {};
var center = self.parseCenter(zr, serie.center);
var centerX = center[0]; // 圆心横坐标
var centerY = center[1]; // 圆心纵坐标
// 视觉引导线起点半径
var midRadius = r1;
// 视觉引导线终点半径
var maxRadius = self.parseRadius(zr, serie.radius)[1]
- (-labelLineControl.length)
+ lastAddRadius;
var midAngle = ((endAngle + startAngle) / 2) % 360; // 角度中值
var cosValue = zrMath.cos(midAngle, true);
var sinValue = zrMath.sin(midAngle, true);
// 三角函数缓存已在zrender/tool/math中做了
return {
shape : 'brokenLine',
zlevel : _zlevelBase + 1,
hoverable : false,
style : {
pointList : [
[
centerX + midRadius * cosValue,
centerY - midRadius * sinValue
],
[
centerX + maxRadius * cosValue,
centerY - maxRadius * sinValue
],
[
data.__labelX,
data.__labelY
]
],
//xStart : centerX + midRadius * cosValue,
//yStart : centerY - midRadius * sinValue,
//xEnd : centerX + maxRadius * cosValue,
//yEnd : centerY - maxRadius * sinValue,
strokeColor : lineStyle.color || defaultColor,
lineType : lineStyle.type,
lineWidth : lineStyle.width
},
_seriesIndex : seriesIndex,
_dataIndex : dataIndex
};
}
else {
return;
}
}
/**
* 返回特定状态(normal or emphasis)下是否需要显示label标签文本
* @param {Object} serie
* @param {Object} data
* @param {boolean} isEmphasis true is 'emphasis' and false is 'normal'
*/
function _needLabel(serie, data, isEmphasis) {
return self.deepQuery(
[data, serie],
'itemStyle.'
+ (isEmphasis ? 'emphasis' : 'normal')
+ '.label.show'
);
}
/**
* 返回特定状态(normal or emphasis)下是否需要显示labelLine标签视觉引导线
* @param {Object} serie
* @param {Object} data
* @param {boolean} isEmphasis true is 'emphasis' and false is 'normal'
*/
function _needLabelLine(serie, data, isEmphasis) {
return self.deepQuery(
[data, serie],
'itemStyle.'
+ (isEmphasis ? 'emphasis' : 'normal')
+'.labelLine.show'
);
}
/**
* 参数修正&默认值赋值,重载基类方法
* @param {Object} opt 参数
*/
function reformOption(opt) {
// 常用方法快捷方式
var _merge = zrUtil.merge;
opt = _merge(
opt || {},
ecConfig.pie,
{
'overwrite' : false,
'recursive' : true
}
);
// 通用字体设置
opt.itemStyle.normal.label.textStyle = _merge(
opt.itemStyle.normal.label.textStyle || {},
ecConfig.textStyle,
{
'overwrite' : false,
'recursive' : true
}
);
opt.itemStyle.emphasis.label.textStyle = _merge(
opt.itemStyle.emphasis.label.textStyle || {},
ecConfig.textStyle,
{
'overwrite' : false,
'recursive' : true
}
);
return opt;
}
/**
* 构造函数默认执行的初始化方法,也用于创建实例后动态修改
* @param {Object} newSeries
* @param {Object} newComponent
*/
function init(newOption, newComponent) {
component = newComponent;
refresh(newOption);
}
/**
* 刷新
*/
function refresh(newOption) {
if (newOption) {
option = newOption;
series = option.series;
}
self.clear();
_buildShape();
}
/**
* 动态数据增加动画
* 心跳效果
function addDataAnimation(params) {
var aniMap = {}; // seriesIndex索引参数
for (var i = 0, l = params.length; i < l; i++) {
aniMap[params[i][0]] = params[i];
}
var x;
var y;
var r;
var seriesIndex;
for (var i = self.shapeList.length - 1; i >= 0; i--) {
seriesIndex = ecData.get(self.shapeList[i], 'seriesIndex');
if (aniMap[seriesIndex]) {
if (self.shapeList[i].shape == 'sector'
|| self.shapeList[i].shape == 'circle'
|| self.shapeList[i].shape == 'ring'
) {
r = self.shapeList[i].style.r;
zr.animate(self.shapeList[i].id, 'style')
.when(
300,
{r : r * 0.9}
)
.when(
500,
{r : r}
)
.start();
}
}
}
}
*/
/**
* 动态数据增加动画
*/
function addDataAnimation(params) {
var aniMap = {}; // seriesIndex索引参数
for (var i = 0, l = params.length; i < l; i++) {
aniMap[params[i][0]] = params[i];
}
// 构建新的饼图匹配差异做动画
var sectorMap = {};
var textMap = {};
var lineMap = {};
var backupShapeList = zrUtil.clone(self.shapeList);
self.shapeList = [];
var seriesIndex;
var isHead;
var dataGrow;
var deltaIdxMap = {}; // 修正新增数据后会对dataIndex产生错位匹配
for (var i = 0, l = params.length; i < l; i++) {
seriesIndex = params[i][0];
isHead = params[i][2];
dataGrow = params[i][3];
if (series[seriesIndex]
&& series[seriesIndex].type == ecConfig.CHART_TYPE_PIE
) {
if (isHead) {
if (!dataGrow) {
sectorMap[
seriesIndex
+ '_'
+ series[seriesIndex].data.length
] = 'delete';
}
deltaIdxMap[seriesIndex] = 1;
}
else {
if (!dataGrow) {
sectorMap[seriesIndex + '_-1'] = 'delete';
deltaIdxMap[seriesIndex] = -1;
}
else {
deltaIdxMap[seriesIndex] = 0;
}
}
_buildSinglePie(seriesIndex);
}
}
var dataIndex;
var key;
for (var i = 0, l = self.shapeList.length; i < l; i++) {
seriesIndex = self.shapeList[i]._seriesIndex;
dataIndex = self.shapeList[i]._dataIndex;
key = seriesIndex + '_' + dataIndex;
// map映射让n*n变n
switch (self.shapeList[i].shape) {
case 'sector' :
sectorMap[key] = self.shapeList[i];
break;
case 'text' :
textMap[key] = self.shapeList[i];
break;
case 'line' :
lineMap[key] = self.shapeList[i];
break;
}
}
self.shapeList = [];
var targeSector;
for (var i = 0, l = backupShapeList.length; i < l; i++) {
seriesIndex = backupShapeList[i]._seriesIndex;
if (aniMap[seriesIndex]) {
dataIndex = backupShapeList[i]._dataIndex
+ deltaIdxMap[seriesIndex];
key = seriesIndex + '_' + dataIndex;
targeSector = sectorMap[key];
if (!targeSector) {
continue;
}
if (backupShapeList[i].shape == 'sector') {
if (targeSector != 'delete') {
// 原有扇形
zr.animate(backupShapeList[i].id, 'style')
.when(
400,
{
startAngle :
targeSector.style.startAngle,
endAngle :
targeSector.style.endAngle
}
)
.start();
}
else {
// 删除的扇形
zr.animate(backupShapeList[i].id, 'style')
.when(
400,
deltaIdxMap[seriesIndex] < 0
? {
endAngle :
backupShapeList[i].style.startAngle
}
: {
startAngle :
backupShapeList[i].style.endAngle
}
)
.start();
}
}
else if (backupShapeList[i].shape == 'text'
|| backupShapeList[i].shape == 'line'
) {
if (targeSector == 'delete') {
// 删除逻辑一样
zr.delShape(backupShapeList[i].id);
}
else {
// 懒得新建变量了,借用一下
switch (backupShapeList[i].shape) {
case 'text':
targeSector = textMap[key];
zr.animate(backupShapeList[i].id, 'style')
.when(
400,
{
x :targeSector.style.x,
y :targeSector.style.y
}
)
.start();
break;
case 'line':
targeSector = lineMap[key];
zr.animate(backupShapeList[i].id, 'style')
.when(
400,
{
xStart:targeSector.style.xStart,
yStart:targeSector.style.yStart,
xEnd : targeSector.style.xEnd,
yEnd : targeSector.style.yEnd
}
)
.start();
break;
}
}
}
}
}
self.shapeList = backupShapeList;
}
/**
* 动画设定
*/
function animation() {
var duration = self.query(option, 'animationDuration');
var easing = self.query(option, 'animationEasing');
var x;
var y;
var r0;
var r;
var serie;
var dataIndex;
for (var i = 0, l = self.shapeList.length; i < l; i++) {
if (self.shapeList[i].shape == 'sector'
|| self.shapeList[i].shape == 'circle'
|| self.shapeList[i].shape == 'ring'
) {
x = self.shapeList[i].style.x;
y = self.shapeList[i].style.y;
r0 = self.shapeList[i].style.r0;
r = self.shapeList[i].style.r;
zr.modShape(
self.shapeList[i].id,
{
rotation : [Math.PI*2, x, y],
style : {
r0 : 0,
r : 0
}
},
true
);
serie = ecData.get(self.shapeList[i], 'series');
dataIndex = ecData.get(self.shapeList[i], 'dataIndex');
zr.animate(self.shapeList[i].id, 'style')
.when(
(self.query(serie,'animationDuration')
|| duration)
+ dataIndex * 10,
{
r0 : r0,
r : r
}
)
.start('QuinticOut');
zr.animate(self.shapeList[i].id, '')
.when(
(self.query(serie,'animationDuration')
|| duration)
+ dataIndex * 100,
{rotation : [0, x, y]}
)
.start(
self.query(serie, 'animationEasing') || easing
);
}
else if (!self.shapeList[i]._mark){
dataIndex = self.shapeList[i]._dataIndex;
zr.modShape(
self.shapeList[i].id,
{
scale : [0, 0, x, y]
},
true
);
zr.animate(self.shapeList[i].id, '')
.when(
duration + dataIndex * 100,
{scale : [1, 1, x, y]}
)
.start('QuinticOut');
}
}
self.animationMark(duration, easing);
}
function onclick(param) {
if (!self.isClick || !param.target) {
// 没有在当前实例上发生点击直接返回
return;
}
var offset; // 偏移
var target = param.target;
var style = target.style;
var seriesIndex = ecData.get(target, 'seriesIndex');
var dataIndex = ecData.get(target, 'dataIndex');
for (var i = 0, len = self.shapeList.length; i < len; i++) {
if (self.shapeList[i].id == target.id) {
seriesIndex = ecData.get(target, 'seriesIndex');
dataIndex = ecData.get(target, 'dataIndex');
// 当前点击的
if (!style._hasSelected) {
var midAngle =
((style.startAngle + style.endAngle) / 2)
.toFixed(2) - 0;
target.style._hasSelected = true;
_selected[seriesIndex][dataIndex] = true;
target.style._x = target.style.x;
target.style._y = target.style.y;
offset = self.query(
series[seriesIndex],
'selectedOffset'
);
target.style.x += zrMath.cos(midAngle, true)
* offset;
target.style.y -= zrMath.sin(midAngle, true)
* offset;
}
else {
// 复位
target.style.x = target.style._x;
target.style.y = target.style._y;
target.style._hasSelected = false;
_selected[seriesIndex][dataIndex] = false;
}
zr.modShape(target.id, target);
}
else if (self.shapeList[i].style._hasSelected
&& _selectedMode == 'single'
) {
seriesIndex = ecData.get(self.shapeList[i], 'seriesIndex');
dataIndex = ecData.get(self.shapeList[i], 'dataIndex');
// 单选模式下需要取消其他已经选中的
self.shapeList[i].style.x = self.shapeList[i].style._x;
self.shapeList[i].style.y = self.shapeList[i].style._y;
self.shapeList[i].style._hasSelected = false;
_selected[seriesIndex][dataIndex] = false;
zr.modShape(
self.shapeList[i].id, self.shapeList[i]
);
}
}
messageCenter.dispatch(
ecConfig.EVENT.PIE_SELECTED,
param.event,
{selected : _selected}
);
zr.refresh();
}
/**
* 数据项被拖拽进来, 重载基类方法
*/
function ondrop(param, status) {
if (!self.isDrop || !param.target) {
// 没有在当前实例上发生拖拽行为则直接返回
return;
}
var target = param.target; // 拖拽安放目标
var dragged = param.dragged; // 当前被拖拽的图形对象
var seriesIndex = ecData.get(target, 'seriesIndex');
var dataIndex = ecData.get(target, 'dataIndex');
var data;
var legend = component.legend;
if (dataIndex == -1) {
// 落到pieCase上,数据被拖拽进某个饼图,增加数据
data = {
value : ecData.get(dragged, 'value'),
name : ecData.get(dragged, 'name')
};
// 修饼图数值不为负值
if (data.value < 0) {
data.value = 0;
}
series[seriesIndex].data.push(data);
legend && legend.add(
data.name,
dragged.style.color || dragged.style.strokeColor
);
}
else {
// 落到sector上,数据被拖拽到某个数据项上,数据修改
var accMath = require('../util/accMath');
data = series[seriesIndex].data[dataIndex];
legend && legend.del(data.name);
data.name += option.nameConnector
+ ecData.get(dragged, 'name');
data.value = accMath.accAdd(
data.value,
ecData.get(dragged, 'value')
);
legend && legend.add(
data.name,
dragged.style.color || dragged.style.strokeColor
);
}
// 别status = {}赋值啊!!
status.dragIn = status.dragIn || true;
// 处理完拖拽事件后复位
self.isDrop = false;
return;
}
/**
* 数据项被拖拽出去,重载基类方法
*/
function ondragend(param, status) {
if (!self.isDragend || !param.target) {
// 没有在当前实例上发生拖拽行为则直接返回
return;
}
var target = param.target; // 被拖拽图形元素
var seriesIndex = ecData.get(target, 'seriesIndex');
var dataIndex = ecData.get(target, 'dataIndex');
// 被拖拽的图形是饼图sector,删除被拖拽走的数据
component.legend && component.legend.del(
series[seriesIndex].data[dataIndex].name
);
series[seriesIndex].data.splice(dataIndex, 1);
// 别status = {}赋值啊!!
status.dragOut = true;
status.needRefresh = true;
// 处理完拖拽事件后复位
self.isDragend = false;
return;
}
/**
* 输出动态视觉引导线
*/
self.shapeHandler.onmouseover = function(param) {
var shape = param.target;
var seriesIndex = ecData.get(shape, 'seriesIndex');
var dataIndex = ecData.get(shape, 'dataIndex');
var percent = ecData.get(shape, 'special');
var lastAddRadius = shape._lastAddRadius;
var startAngle = shape.style.startAngle;
var endAngle = shape.style.endAngle;
var defaultColor = shape.highlightStyle.color;
// 文本标签,需要显示则会有返回
var label = _getLabel(
seriesIndex, dataIndex, percent, lastAddRadius,
startAngle, endAngle, defaultColor,
true
);
if (label) {
zr.addHoverShape(label);
}
// 文本标签视觉引导线,需要显示则会有返回
var labelLine = _getLabelLine(
seriesIndex, dataIndex, lastAddRadius,
shape.style.r0, shape.style.r,
startAngle, endAngle, defaultColor,
true
);
if (labelLine) {
zr.addHoverShape(labelLine);
}
};
self.reformOption = reformOption; // 重载基类方法
self.animation = animation;
// 接口方法
self.init = init;
self.refresh = refresh;
self.addDataAnimation = addDataAnimation;
self.onclick = onclick;
self.ondrop = ondrop;
self.ondragend = ondragend;
init(option, component);
}
// 图表注册
require('../chart').define('pie', Pie);
return Pie;
});