You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
459 lines
16 KiB
459 lines
16 KiB
4 years ago
|
/**
|
||
|
* echarts图表类:雷达图
|
||
|
*
|
||
|
* @desc echarts基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据统计图表。
|
||
|
* @author Neil (杨骥, 511415343@qq.com)
|
||
|
*/
|
||
|
|
||
|
define(function (require) {
|
||
|
var ChartBase = require('./base');
|
||
|
|
||
|
// 图形依赖
|
||
|
var PolygonShape = require('zrender/shape/Polygon');
|
||
|
// 组件依赖
|
||
|
require('../component/polar');
|
||
|
|
||
|
var ecConfig = require('../config');
|
||
|
// 雷达图默认参数
|
||
|
ecConfig.radar = {
|
||
|
zlevel: 0, // 一级层叠
|
||
|
z: 2, // 二级层叠
|
||
|
clickable: true,
|
||
|
legendHoverLink: true,
|
||
|
polarIndex: 0,
|
||
|
itemStyle: {
|
||
|
normal: {
|
||
|
// color: 各异,
|
||
|
label: {
|
||
|
show: false
|
||
|
},
|
||
|
lineStyle: {
|
||
|
width: 2,
|
||
|
type: 'solid'
|
||
|
}
|
||
|
},
|
||
|
emphasis: {
|
||
|
// color: 各异,
|
||
|
label: {
|
||
|
show: false
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
// symbol: null, // 拐点图形类型
|
||
|
symbolSize: 2 // 可计算特性参数,空数据拖拽提示图形大小
|
||
|
// symbolRotate: null, // 图形旋转控制
|
||
|
};
|
||
|
|
||
|
var ecData = require('../util/ecData');
|
||
|
var zrUtil = require('zrender/tool/util');
|
||
|
var zrColor = require('zrender/tool/color');
|
||
|
|
||
|
/**
|
||
|
* 构造函数
|
||
|
* @param {Object} messageCenter echart消息中心
|
||
|
* @param {ZRender} zr zrender实例
|
||
|
* @param {Object} series 数据
|
||
|
* @param {Object} component 组件
|
||
|
* @constructor
|
||
|
* @exports Radar
|
||
|
*/
|
||
|
function Radar(ecTheme, messageCenter, zr, option, myChart) {
|
||
|
// 图表基类
|
||
|
ChartBase.call(this, ecTheme, messageCenter, zr, option, myChart);
|
||
|
|
||
|
this.refresh(option);
|
||
|
}
|
||
|
|
||
|
Radar.prototype = {
|
||
|
type : ecConfig.CHART_TYPE_RADAR,
|
||
|
/**
|
||
|
* 绘制图形
|
||
|
*/
|
||
|
_buildShape : function () {
|
||
|
this.selectedMap = {};
|
||
|
this._symbol = this.option.symbolList;
|
||
|
this._queryTarget;
|
||
|
this._dropBoxList = [];
|
||
|
this._radarDataCounter = 0;
|
||
|
|
||
|
var series = this.series;
|
||
|
var legend = this.component.legend;
|
||
|
var serieName;
|
||
|
for (var i = 0, l = series.length; i < l ; i++) {
|
||
|
if (series[i].type === ecConfig.CHART_TYPE_RADAR) {
|
||
|
this.serie = this.reformOption(series[i]);
|
||
|
this.legendHoverLink = series[i].legendHoverLink || this.legendHoverLink;
|
||
|
serieName = this.serie.name || '';
|
||
|
// 系列图例开关
|
||
|
this.selectedMap[serieName] =
|
||
|
legend ? legend.isSelected(serieName) : true;
|
||
|
|
||
|
if (this.selectedMap[serieName]) {
|
||
|
this._queryTarget = [this.serie, this.option];
|
||
|
|
||
|
// 添加可拖拽提示框,多系列共用一个极坐标,第一个优先
|
||
|
if (this.deepQuery(this._queryTarget, 'calculable')) {
|
||
|
this._addDropBox(i);
|
||
|
}
|
||
|
this._buildSingleRadar(i);
|
||
|
this.buildMark(i);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.addShapeList();
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 构建数据图形
|
||
|
* @param {number} 序列的index
|
||
|
*/
|
||
|
_buildSingleRadar : function (index) {
|
||
|
var legend = this.component.legend;
|
||
|
var iconShape;
|
||
|
var data = this.serie.data;
|
||
|
var defaultColor;
|
||
|
var name;
|
||
|
var pointList;
|
||
|
var calculable = this.deepQuery(this._queryTarget, 'calculable');
|
||
|
|
||
|
for (var i = 0; i < data.length; i++) {
|
||
|
name = data[i].name || '';
|
||
|
|
||
|
// 图例开关
|
||
|
this.selectedMap[name] = legend
|
||
|
? legend.isSelected(name) : true;
|
||
|
if (!this.selectedMap[name]) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// 默认颜色策略
|
||
|
if (legend) {
|
||
|
// 有图例则从图例中获取颜色定义
|
||
|
defaultColor = legend.getColor(name);
|
||
|
iconShape = legend.getItemShape(name);
|
||
|
if (iconShape) {
|
||
|
// 回调legend,换一个更形象的icon
|
||
|
iconShape.style.brushType = this.deepQuery(
|
||
|
[data[i], this.serie], 'itemStyle.normal.areaStyle'
|
||
|
) ? 'both' : 'stroke';
|
||
|
legend.setItemShape(name, iconShape);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// 全局颜色定义
|
||
|
defaultColor = this.zr.getColor(i);
|
||
|
}
|
||
|
|
||
|
pointList = this._getPointList(this.serie.polarIndex, data[i]);
|
||
|
// 添加拐点形状
|
||
|
this._addSymbol(
|
||
|
pointList, defaultColor, i, index, this.serie.polarIndex);
|
||
|
// 添加数据形状
|
||
|
this._addDataShape(
|
||
|
pointList, defaultColor, data[i],
|
||
|
index, i, calculable
|
||
|
);
|
||
|
this._radarDataCounter++;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 获取数据的点集
|
||
|
* @param {number} polarIndex
|
||
|
* @param {Array<Object>} 处理的数据
|
||
|
* @return {Array<Array<number>>} 点集
|
||
|
*/
|
||
|
_getPointList : function (polarIndex, dataArr) {
|
||
|
var pointList = [];
|
||
|
var vector;
|
||
|
var polar = this.component.polar;
|
||
|
|
||
|
var value;
|
||
|
for (var i = 0, l = dataArr.value.length; i < l; i++) {
|
||
|
value = this.getDataFromOption(dataArr.value[i]);
|
||
|
vector = value != '-'
|
||
|
? polar.getVector(polarIndex, i, value)
|
||
|
: false;
|
||
|
if (vector) {
|
||
|
pointList.push(vector);
|
||
|
}
|
||
|
}
|
||
|
return pointList;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 添加拐点
|
||
|
* @param {Array<Array<number>>} pointList 点集
|
||
|
* @param {string} defaultColor 默认填充颜色
|
||
|
* @param {object} data 数据
|
||
|
* @param {number} serieIndex
|
||
|
*/
|
||
|
_addSymbol :function (pointList, defaultColor, dataIndex, seriesIndex, polarIndex) {
|
||
|
var series = this.series;
|
||
|
var itemShape;
|
||
|
var polar = this.component.polar;
|
||
|
|
||
|
for (var i = 0, l = pointList.length; i < l; i++) {
|
||
|
itemShape = this.getSymbolShape(
|
||
|
this.deepMerge(
|
||
|
[series[seriesIndex].data[dataIndex], series[seriesIndex]]
|
||
|
),
|
||
|
seriesIndex,
|
||
|
series[seriesIndex].data[dataIndex].value[i], i,
|
||
|
polar.getIndicatorText(polarIndex, i),
|
||
|
pointList[i][0], // x
|
||
|
pointList[i][1], // y
|
||
|
this._symbol[this._radarDataCounter % this._symbol.length],
|
||
|
defaultColor,
|
||
|
'#fff',
|
||
|
'vertical'
|
||
|
);
|
||
|
itemShape.zlevel = this.getZlevelBase();
|
||
|
itemShape.z = this.getZBase() + 1;
|
||
|
|
||
|
ecData.set(itemShape, 'data', series[seriesIndex].data[dataIndex]);
|
||
|
ecData.set(itemShape, 'value', series[seriesIndex].data[dataIndex].value);
|
||
|
ecData.set(itemShape, 'dataIndex', dataIndex);
|
||
|
ecData.set(itemShape, 'special', i);
|
||
|
this.shapeList.push(itemShape);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 添加数据图形
|
||
|
* @param {Array<Array<number>>} pointList 点集
|
||
|
* @param {string} defaultColor 默认填充颜色
|
||
|
* @param {object} data 数据
|
||
|
* @param {number} serieIndex
|
||
|
* @param {number} dataIndex
|
||
|
* @param {boolean} calcalable
|
||
|
*/
|
||
|
_addDataShape : function (
|
||
|
pointList, defaultColor, data,
|
||
|
seriesIndex, dataIndex, calculable
|
||
|
) {
|
||
|
var series = this.series;
|
||
|
// 多级控制
|
||
|
var queryTarget = [data, this.serie];
|
||
|
var nColor = this.getItemStyleColor(
|
||
|
this.deepQuery(
|
||
|
queryTarget, 'itemStyle.normal.color'
|
||
|
),
|
||
|
seriesIndex,
|
||
|
dataIndex,
|
||
|
data
|
||
|
);
|
||
|
var nLineWidth = this.deepQuery(
|
||
|
queryTarget, 'itemStyle.normal.lineStyle.width'
|
||
|
);
|
||
|
var nLineType = this.deepQuery(
|
||
|
queryTarget, 'itemStyle.normal.lineStyle.type'
|
||
|
);
|
||
|
var nAreaColor = this.deepQuery(
|
||
|
queryTarget, 'itemStyle.normal.areaStyle.color'
|
||
|
);
|
||
|
var nIsAreaFill = this.deepQuery(
|
||
|
queryTarget, 'itemStyle.normal.areaStyle'
|
||
|
);
|
||
|
var shape = {
|
||
|
zlevel: this.getZlevelBase(),
|
||
|
z: this.getZBase(),
|
||
|
style : {
|
||
|
pointList : pointList,
|
||
|
brushType : nIsAreaFill ? 'both' : 'stroke',
|
||
|
color : nAreaColor
|
||
|
|| nColor
|
||
|
|| (typeof defaultColor === 'string'
|
||
|
? zrColor.alpha(defaultColor,0.5) : defaultColor),
|
||
|
strokeColor : nColor || defaultColor,
|
||
|
lineWidth : nLineWidth,
|
||
|
lineType : nLineType
|
||
|
},
|
||
|
highlightStyle : {
|
||
|
brushType : this.deepQuery(
|
||
|
queryTarget,
|
||
|
'itemStyle.emphasis.areaStyle'
|
||
|
) || nIsAreaFill
|
||
|
? 'both' : 'stroke',
|
||
|
color : this.deepQuery(
|
||
|
queryTarget,
|
||
|
'itemStyle.emphasis.areaStyle.color'
|
||
|
)
|
||
|
|| nAreaColor
|
||
|
|| nColor
|
||
|
|| (typeof defaultColor === 'string'
|
||
|
? zrColor.alpha(defaultColor,0.5) : defaultColor),
|
||
|
strokeColor : this.getItemStyleColor(
|
||
|
this.deepQuery(
|
||
|
queryTarget, 'itemStyle.emphasis.color'
|
||
|
),
|
||
|
seriesIndex,
|
||
|
dataIndex,
|
||
|
data
|
||
|
)
|
||
|
|| nColor || defaultColor,
|
||
|
lineWidth : this.deepQuery(
|
||
|
queryTarget,
|
||
|
'itemStyle.emphasis.lineStyle.width'
|
||
|
) || nLineWidth,
|
||
|
lineType : this.deepQuery(
|
||
|
queryTarget,
|
||
|
'itemStyle.emphasis.lineStyle.type'
|
||
|
) || nLineType
|
||
|
}
|
||
|
};
|
||
|
ecData.pack(
|
||
|
shape,
|
||
|
series[seriesIndex], // 系列
|
||
|
seriesIndex, // 系列索引
|
||
|
data, // 数据
|
||
|
dataIndex, // 数据索引
|
||
|
data.name, // 数据名称
|
||
|
// 附加指标信息
|
||
|
this.component.polar.getIndicator(series[seriesIndex].polarIndex)
|
||
|
);
|
||
|
if (calculable) {
|
||
|
shape.draggable = true;
|
||
|
this.setCalculable(shape);
|
||
|
}
|
||
|
|
||
|
shape = new PolygonShape(shape);
|
||
|
this.shapeList.push(shape);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 增加外围接受框
|
||
|
* @param {number} serie的序列
|
||
|
*/
|
||
|
_addDropBox : function (index) {
|
||
|
var series = this.series;
|
||
|
var polarIndex = this.deepQuery(
|
||
|
this._queryTarget, 'polarIndex'
|
||
|
);
|
||
|
if (!this._dropBoxList[polarIndex]) {
|
||
|
var shape = this.component.polar.getDropBox(polarIndex);
|
||
|
shape.zlevel = this.getZlevelBase();
|
||
|
shape.z = this.getZBase();
|
||
|
|
||
|
this.setCalculable(shape);
|
||
|
ecData.pack(shape, series, index, undefined, -1);
|
||
|
this.shapeList.push(shape);
|
||
|
this._dropBoxList[polarIndex] = true;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 数据项被拖拽出去,重载基类方法
|
||
|
*/
|
||
|
ondragend : function (param, status) {
|
||
|
var series = this.series;
|
||
|
if (!this.isDragend || !param.target) {
|
||
|
// 没有在当前实例上发生拖拽行为则直接返回
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// 被拖拽图形元素
|
||
|
var target = param.target;
|
||
|
|
||
|
var seriesIndex = ecData.get(target, 'seriesIndex');
|
||
|
var dataIndex = ecData.get(target, 'dataIndex');
|
||
|
|
||
|
// 被拖拽的图形是饼图sector,删除被拖拽走的数据
|
||
|
this.component.legend && this.component.legend.del(
|
||
|
series[seriesIndex].data[dataIndex].name
|
||
|
);
|
||
|
|
||
|
series[seriesIndex].data.splice(dataIndex, 1);
|
||
|
|
||
|
// 别status = {}赋值啊!!
|
||
|
status.dragOut = true;
|
||
|
status.needRefresh = true;
|
||
|
|
||
|
// 处理完拖拽事件后复位
|
||
|
this.isDragend = false;
|
||
|
|
||
|
return;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 数据项被拖拽进来, 重载基类方法
|
||
|
*/
|
||
|
ondrop : function (param, status) {
|
||
|
var series = this.series;
|
||
|
if (!this.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 = this.component.legend;
|
||
|
var value;
|
||
|
|
||
|
if (dataIndex === -1) {
|
||
|
data = {
|
||
|
value : ecData.get(dragged, 'value'),
|
||
|
name : ecData.get(dragged, 'name')
|
||
|
};
|
||
|
|
||
|
series[seriesIndex].data.push(data);
|
||
|
|
||
|
legend && legend.add(
|
||
|
data.name,
|
||
|
dragged.style.color || dragged.style.strokeColor
|
||
|
);
|
||
|
}
|
||
|
else {
|
||
|
// 数据被拖拽到某个数据项上,数据修改
|
||
|
var accMath = require('../util/accMath');
|
||
|
data = series[seriesIndex].data[dataIndex];
|
||
|
legend && legend.del(data.name);
|
||
|
data.name += this.option.nameConnector
|
||
|
+ ecData.get(dragged, 'name');
|
||
|
value = ecData.get(dragged, 'value');
|
||
|
for (var i = 0 ; i < value.length; i++) {
|
||
|
data.value[i] = accMath.accAdd(data.value[i], value[i]);
|
||
|
}
|
||
|
|
||
|
legend && legend.add(
|
||
|
data.name,
|
||
|
dragged.style.color || dragged.style.strokeColor
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// 别status = {}赋值啊!!
|
||
|
status.dragIn = status.dragIn || true;
|
||
|
|
||
|
// 处理完拖拽事件后复位
|
||
|
this.isDrop = false;
|
||
|
|
||
|
return;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 刷新
|
||
|
*/
|
||
|
refresh : function (newOption) {
|
||
|
if (newOption) {
|
||
|
this.option = newOption;
|
||
|
this.series = newOption.series;
|
||
|
}
|
||
|
|
||
|
this.backupShapeList();
|
||
|
this._buildShape();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
zrUtil.inherits(Radar, ChartBase);
|
||
|
|
||
|
// 图表注册
|
||
|
require('../chart').define('radar', Radar);
|
||
|
|
||
|
return Radar;
|
||
|
});
|