/** * echarts图表类:雷达图 * * @desc echarts基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据统计图表。 * @author Neil (杨骥, yangji01@baidu.com) * */ define(function(require) { /** * 构造函数 * @param {Object} messageCenter echart消息中心 * @param {ZRender} zr zrender实例 * @param {Object} series 数据 * @param {Object} component 组件 */ function Radar(messageCenter, zr, option, component) { // 基类装饰 var ComponentBase = require('../component/base'); ComponentBase.call(this, zr); // 可计算特性装饰 var CalculableBase = require('./calculableBase'); CalculableBase.call(this, zr, option); var ecConfig = require('../config'); var ecData = require('../util/ecData'); var zrColor = require('zrender/tool/color'); var self = this; self.type = ecConfig.CHART_TYPE_RADAR; var series; // 共享数据源,不要修改跟自己无关的项 var serie; var _zlevelBase = self.getZlevelBase(); var _queryTarget; var _dropBoxList; var _symbol = [ 'circle', 'rectangle', 'triangle', 'diamond', 'emptyCircle', 'emptyRectangle', 'emptyTriangle', 'emptyDiamond' ]; var _radarDataCounter; /** * 绘制图形 */ function _buildShape() { self.selectedMap = {}; _dropBoxList = []; _radarDataCounter = 0; for (var i = 0, l = series.length; i < l ; i ++) { if (series[i].type == ecConfig.CHART_TYPE_RADAR) { serie = self.reformOption(series[i]); _queryTarget = [serie, option]; // 添加可拖拽提示框,多系列共用一个极坐标,第一个优先 if (self.deepQuery(_queryTarget, 'calculable')) { _addDropBox(i); } _buildSingleRadar(i); } } 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} 序列的index */ function _buildSingleRadar(index) { var legend = component.legend; var iconShape; var data = serie.data; var defaultColor; var name; var pointList; var calculable = self.deepQuery(_queryTarget, 'calculable'); for (var i = 0; i < data.length; i ++) { name = data[i].name || ''; // 图例开关 self.selectedMap[name] = legend ? legend.isSelected(name) : true; if (!self.selectedMap[name]) { continue; } // 默认颜色策略 if (legend) { // 有图例则从图例中获取颜色定义 defaultColor = legend.getColor(name); iconShape = legend.getItemShape(name); if (iconShape) { // 回调legend,换一个更形象的icon iconShape.style.brushType = self.deepQuery( [data[i], serie], 'itemStyle.normal.areaStyle' ) ? 'both' : 'stroke'; legend.setItemShape(name, iconShape); } } else { // 全局颜色定义 defaultColor = zr.getColor(i); } pointList = _getPointList(serie.polarIndex, data[i]); // 添加拐点形状 _addSymbol(pointList, defaultColor, data[i], index); // 添加数据形状 _addDataShape( pointList, defaultColor, data[i], index, i, calculable ); _radarDataCounter++; } } /** * 获取数据的点集 * @param {number} polarIndex * @param {Array} 处理的数据 * @return {Array>} 点集 */ function _getPointList(polarIndex, dataArr) { var pointList = []; var vector; var polar = component.polar; for (var i = 0, l = dataArr.value.length; i < l; i++) { vector = polar.getVector(polarIndex, i, dataArr.value[i]); if (vector) { pointList.push(vector); } } return pointList; } /** * 生成折线图上的拐点图形 */ function _getSymbol( x, y, symbol, symbolSize, normalColor, emphasisColor, lineWidth ) { var itemShape = { shape : 'icon', zlevel : _zlevelBase + 1, style : { iconType : symbol.replace('empty', '').toLowerCase(), x : x - symbolSize, y : y - symbolSize, width : symbolSize * 2, height : symbolSize * 2, brushType : 'both', color : symbol.match('empty') ? '#fff' : normalColor, strokeColor : normalColor, lineWidth: lineWidth * 2 }, hoverable: false }; if (symbol.match('star')) { itemShape.style.iconType = 'star'; itemShape.style.n = (symbol.replace('empty', '').replace('star','') - 0) || 5; } itemShape._x = x; itemShape._y = y; return itemShape; } /** * 添加拐点 * @param {Array>} pointList 点集 * @param {string} defaultColor 默认填充颜色 * @param {object} data 数据 * @param {number} serieIndex */ function _addSymbol(pointList, defaultColor, data) { // 多级控制 var queryTarget = [data, serie]; var symbol = self.deepQuery(queryTarget,'symbol') || _symbol[_radarDataCounter % _symbol.length] || 'cricle'; if (symbol != 'none') { var symbolSize = self.deepQuery(queryTarget,'symbolSize'); var nColor = self.deepQuery( queryTarget, 'itemStyle.normal.color' ); var eColor = self.deepQuery( queryTarget, 'itemStyle.emphasis.color' ); var lineWidth = self.deepQuery( queryTarget, 'itemStyle.normal.lineStyle.width' ); for (var i = 0, l = pointList.length; i < l; i++) { self.shapeList.push(_getSymbol( pointList[i][0], // x pointList[i][1], // y symbol, symbolSize, nColor || defaultColor, eColor || nColor || defaultColor, lineWidth )); } } } /** * 添加数据图形 * @param {Array>} pointList 点集 * @param {string} defaultColor 默认填充颜色 * @param {object} data 数据 * @param {number} serieIndex * @param {number} dataIndex * @param {boolean} calcalable */ function _addDataShape( pointList, defaultColor, data, seriesIndex, dataIndex, calculable ) { // 多级控制 var queryTarget = [data, serie]; var nColor = self.deepQuery( queryTarget, 'itemStyle.normal.color' ); var nLineWidth = self.deepQuery( queryTarget, 'itemStyle.normal.lineStyle.width' ); var nLineType = self.deepQuery( queryTarget, 'itemStyle.normal.lineStyle.type' ); var nAreaColor = self.deepQuery( queryTarget, 'itemStyle.normal.areaStyle.color' ); var nIsAreaFill = self.deepQuery( queryTarget, 'itemStyle.normal.areaStyle' ); var shape = { shape : 'polygon', zlevel : _zlevelBase, style : { pointList : pointList, brushType : nIsAreaFill ? 'both' : 'stroke', color : nAreaColor || nColor || zrColor.alpha(defaultColor,0.5), strokeColor : nColor || defaultColor, lineWidth : nLineWidth, lineType : nLineType }, highlightStyle : { brushType : self.deepQuery( queryTarget, 'itemStyle.emphasis.areaStyle' ) || nIsAreaFill ? 'both' : 'stroke', color : self.deepQuery( queryTarget, 'itemStyle.emphasis.areaStyle.color' ) || nAreaColor || nColor || zrColor.alpha(defaultColor,0.5), strokeColor : self.deepQuery( queryTarget, 'itemStyle.emphasis.color' ) || nColor || defaultColor, lineWidth : self.deepQuery( queryTarget, 'itemStyle.emphasis.lineStyle.width' ) || nLineWidth, lineType : self.deepQuery( queryTarget, 'itemStyle.emphasis.lineStyle.type' ) || nLineType } }; ecData.pack( shape, series[seriesIndex], // 系列 seriesIndex, // 系列索引 data, // 数据 dataIndex, // 数据索引 data.name, // 数据名称 // 附加指标信息 component.polar.getIndicator(series[seriesIndex].polarIndex) ); if (calculable) { shape.draggable = true; self.setCalculable(shape); } self.shapeList.push(shape); } /** * 增加外围接受框 * @param {number} serie的序列 */ function _addDropBox(index) { var polarIndex = self.deepQuery( _queryTarget, 'polarIndex' ); if (!_dropBoxList[polarIndex]) { var shape = component.polar.getDropBox(polarIndex); shape.zlevel = _zlevelBase; self.setCalculable(shape); ecData.pack(shape, series, index, undefined, -1); self.shapeList.push(shape); _dropBoxList[polarIndex] = true; } } /** * 数据项被拖拽出去,重载基类方法 */ 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; } /** * 数据项被拖拽进来, 重载基类方法 */ 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; 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 { data = series[seriesIndex].data[dataIndex]; legend && legend.del(data.name); data.name += option.nameConnector + ecData.get(dragged, 'name'); value = ecData.get(dragged, 'value'); for (var i = 0 ; i < value.length; i ++) { data.value[i] += value[i]; } legend && legend.add( data.name, dragged.style.color || dragged.style.strokeColor ); } // 别status = {}赋值啊!! status.dragIn = status.dragIn || true; // 处理完拖拽事件后复位 self.isDrop = false; return; } /** * 构造函数默认执行的初始化方法,也用于创建实例后动态修改 * @param {Object} newZr * @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 animation() { var duration = self.deepQuery([option], 'animationDuration'); var easing = self.deepQuery([option], 'animationEasing'); var dataIndex; var seriesIndex; var data; var serie; var polarIndex; var polar = component.polar; var center; var item; var x; var y; for (var i = 0, l = self.shapeList.length; i < l; i++) { if (self.shapeList[i].shape == 'polygon') { item = self.shapeList[i]; seriesIndex = ecData.get(item, 'seriesIndex'); dataIndex = ecData.get(item, 'dataIndex'); serie = series[seriesIndex]; data = serie.data[dataIndex]; polarIndex = self.deepQuery( [data, serie, option], 'polarIndex'); center = polar.getCenter(polarIndex); x = center[0]; y = center[1]; zr.modShape(self.shapeList[i].id, { scale : [0.1, 0.1, x, y] }); zr.animate(item.id, '') .when( (self.deepQuery([serie],'animationDuration') || duration) + dataIndex * 100, {scale : [1, 1, x, y]} ) .start( self.deepQuery([serie], 'animationEasing') || easing ); } else { x = self.shapeList[i]._x || 0; y = self.shapeList[i]._y || 0; zr.modShape(self.shapeList[i].id, { scale : [0, 0, x, y] }); zr.animate(self.shapeList[i].id, '') .when( duration, {scale : [1, 1, x, y]} ) .start('QuinticOut'); } } } self.init = init; self.refresh = refresh; self.animation = animation; self.ondrop = ondrop; self.ondragend = ondragend; init(option, component); } // 图表注册 require('../chart').define('radar', Radar); return Radar; });