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.
979 lines
32 KiB
979 lines
32 KiB
4 years ago
|
/**
|
||
|
* echarts组件类:极坐标
|
||
|
*
|
||
|
* @desc echarts基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据统计图表。
|
||
|
* @author Neil (杨骥, 511415343@qq.com)
|
||
|
*
|
||
|
*/
|
||
|
define(function (require) {
|
||
|
var Base = require('./base');
|
||
|
|
||
|
// 图形依赖
|
||
|
var TextShape = require('zrender/shape/Text');
|
||
|
var LineShape = require('zrender/shape/Line');
|
||
|
var PolygonShape = require('zrender/shape/Polygon');
|
||
|
var Circle = require('zrender/shape/Circle');
|
||
|
var Ring = require('zrender/shape/Ring');
|
||
|
|
||
|
var ecConfig = require('../config');
|
||
|
ecConfig.polar = {
|
||
|
zlevel: 0, // 一级层叠
|
||
|
z: 0, // 二级层叠
|
||
|
center: ['50%', '50%'], // 默认全局居中
|
||
|
radius: '75%',
|
||
|
startAngle: 90,
|
||
|
boundaryGap: [0, 0], // 数值起始和结束两端空白策略
|
||
|
splitNumber: 5,
|
||
|
name: {
|
||
|
show: true,
|
||
|
// formatter: null,
|
||
|
textStyle: { // 其余属性默认使用全局文本样式,详见TEXTSTYLE
|
||
|
color: '#333'
|
||
|
}
|
||
|
},
|
||
|
axisLine: { // 坐标轴线
|
||
|
show: true, // 默认显示,属性show控制显示与否
|
||
|
lineStyle: { // 属性lineStyle控制线条样式
|
||
|
color: '#ccc',
|
||
|
width: 1,
|
||
|
type: 'solid'
|
||
|
}
|
||
|
},
|
||
|
axisLabel: { // 坐标轴文本标签,详见axis.axisLabel
|
||
|
show: false,
|
||
|
// formatter: null,
|
||
|
textStyle: { // 其余属性默认使用全局文本样式,详见TEXTSTYLE
|
||
|
color: '#333'
|
||
|
}
|
||
|
},
|
||
|
splitArea: {
|
||
|
show: true,
|
||
|
areaStyle: {
|
||
|
color: ['rgba(250,250,250,0.3)','rgba(200,200,200,0.3)']
|
||
|
}
|
||
|
},
|
||
|
splitLine: {
|
||
|
show: true,
|
||
|
lineStyle: {
|
||
|
width: 1,
|
||
|
color: '#ccc'
|
||
|
}
|
||
|
},
|
||
|
type: 'polygon'
|
||
|
// indicator: []
|
||
|
};
|
||
|
|
||
|
var zrUtil = require('zrender/tool/util');
|
||
|
var ecCoordinates = require('../util/coordinates');
|
||
|
|
||
|
function Polar(ecTheme, messageCenter, zr, option, myChart) {
|
||
|
Base.call(this, ecTheme, messageCenter, zr, option, myChart);
|
||
|
|
||
|
this.refresh(option);
|
||
|
}
|
||
|
|
||
|
Polar.prototype = {
|
||
|
type : ecConfig.COMPONENT_TYPE_POLAR,
|
||
|
|
||
|
/**
|
||
|
* 绘制图形
|
||
|
*/
|
||
|
_buildShape : function () {
|
||
|
for (var i = 0; i < this.polar.length; i ++) {
|
||
|
this._index = i;
|
||
|
this.reformOption(this.polar[i]);
|
||
|
|
||
|
this._queryTarget = [this.polar[i], this.option];
|
||
|
this._createVector(i);
|
||
|
this._buildSpiderWeb(i);
|
||
|
|
||
|
this._buildText(i);
|
||
|
|
||
|
this._adjustIndicatorValue(i);
|
||
|
this._addAxisLabel(i);
|
||
|
}
|
||
|
|
||
|
for (var i = 0; i < this.shapeList.length; i ++) {
|
||
|
this.zr.addShape(this.shapeList[i]);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 生成蜘蛛网顶点坐标
|
||
|
* @param {number} polar的index
|
||
|
*/
|
||
|
_createVector : function (index) {
|
||
|
var item = this.polar[index];
|
||
|
var indicator = this.deepQuery(this._queryTarget, 'indicator');
|
||
|
var length = indicator.length;
|
||
|
var startAngle = item.startAngle ;
|
||
|
var dStep = 2 * Math.PI / length;
|
||
|
var radius = this._getRadius();
|
||
|
var __ecIndicator = item.__ecIndicator = [];
|
||
|
var vector;
|
||
|
|
||
|
for (var i = 0 ;i < length ; i ++) {
|
||
|
vector = ecCoordinates.polar2cartesian(
|
||
|
radius, startAngle * Math.PI / 180 + dStep * i
|
||
|
);
|
||
|
__ecIndicator.push({
|
||
|
// 将图形翻转
|
||
|
vector : [vector[1], -vector[0]]
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 获取外圈的半径
|
||
|
*
|
||
|
* @return {number}
|
||
|
*/
|
||
|
_getRadius : function () {
|
||
|
var item = this.polar[this._index];
|
||
|
return this.parsePercent(
|
||
|
item.radius,
|
||
|
Math.min(this.zr.getWidth(), this.zr.getHeight()) / 2
|
||
|
);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 构建蜘蛛网
|
||
|
* @param {number} polar的index
|
||
|
*/
|
||
|
_buildSpiderWeb : function (index) {
|
||
|
var item = this.polar[index];
|
||
|
var __ecIndicator = item.__ecIndicator;
|
||
|
var splitArea = item.splitArea;
|
||
|
var splitLine = item.splitLine;
|
||
|
|
||
|
var center = this.getCenter(index);
|
||
|
var splitNumber = item.splitNumber;
|
||
|
|
||
|
var strokeColor = splitLine.lineStyle.color;
|
||
|
var lineWidth = splitLine.lineStyle.width;
|
||
|
var show = splitLine.show;
|
||
|
|
||
|
var axisLine = this.deepQuery(this._queryTarget, 'axisLine');
|
||
|
|
||
|
this._addArea(
|
||
|
__ecIndicator, splitNumber, center,
|
||
|
splitArea, strokeColor, lineWidth, show
|
||
|
);
|
||
|
|
||
|
axisLine.show && this._addLine(
|
||
|
__ecIndicator, center, axisLine
|
||
|
);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 绘制axisLabel
|
||
|
*/
|
||
|
_addAxisLabel : function (index) {
|
||
|
var accMath = require('../util/accMath');
|
||
|
var item = this.polar[index];
|
||
|
var indicator = this.deepQuery(this._queryTarget, 'indicator');
|
||
|
var __ecIndicator = item.__ecIndicator;
|
||
|
var axisLabel;
|
||
|
var vector;
|
||
|
var style;
|
||
|
var newStyle;
|
||
|
var splitNumber = this.deepQuery(this._queryTarget, 'splitNumber');
|
||
|
var center = this.getCenter(index);
|
||
|
var vector;
|
||
|
var value;
|
||
|
var text;
|
||
|
var theta;
|
||
|
// var startAngle = this.deepQuery(this._queryTarget, 'startAngle');
|
||
|
var offset;
|
||
|
var interval;
|
||
|
|
||
|
for (var i = 0; i < indicator.length; i ++) {
|
||
|
axisLabel = this.deepQuery(
|
||
|
[indicator[i], item, this.option], 'axisLabel'
|
||
|
);
|
||
|
|
||
|
if (axisLabel.show) {
|
||
|
var textStyle = this.deepQuery([axisLabel, item, this.option], 'textStyle');
|
||
|
var formatter = this.deepQuery([axisLabel, item], 'formatter');
|
||
|
style = {};
|
||
|
style.textFont = this.getFont(textStyle);
|
||
|
style.color = textStyle.color;
|
||
|
|
||
|
style = zrUtil.merge(style, axisLabel);
|
||
|
style.lineWidth = style.width;
|
||
|
|
||
|
vector = __ecIndicator[i].vector;
|
||
|
value = __ecIndicator[i].value;
|
||
|
theta = i / indicator.length * 2 * Math.PI;
|
||
|
offset = axisLabel.offset || 10;
|
||
|
interval = axisLabel.interval || 0;
|
||
|
|
||
|
if (!value) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for (var j = 1 ; j <= splitNumber; j += interval + 1) {
|
||
|
newStyle = zrUtil.merge({}, style);
|
||
|
text = accMath.accAdd(value.min, accMath.accMul(value.step, j));
|
||
|
|
||
|
if (typeof formatter === 'function') {
|
||
|
text = formatter(text);
|
||
|
}
|
||
|
else if (typeof formatter === 'string') {
|
||
|
text = formatter.replace('{a}','{a0}')
|
||
|
.replace('{a0}', text);
|
||
|
}
|
||
|
else {
|
||
|
text = this.numAddCommas(text);
|
||
|
}
|
||
|
|
||
|
newStyle.text = text;
|
||
|
newStyle.x = j * vector[0] / splitNumber
|
||
|
+ Math.cos(theta) * offset + center[0];
|
||
|
newStyle.y = j * vector[1] / splitNumber
|
||
|
+ Math.sin(theta) * offset + center[1];
|
||
|
|
||
|
this.shapeList.push(new TextShape({
|
||
|
zlevel: this.getZlevelBase(),
|
||
|
z: this.getZBase(),
|
||
|
style : newStyle,
|
||
|
draggable : false,
|
||
|
hoverable : false
|
||
|
}));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 绘制坐标头的文字
|
||
|
* @param {number} polar的index
|
||
|
*/
|
||
|
_buildText : function (index) {
|
||
|
var item = this.polar[index];
|
||
|
var __ecIndicator = item.__ecIndicator;
|
||
|
var vector;
|
||
|
var indicator = this.deepQuery(this._queryTarget, 'indicator');
|
||
|
var center = this.getCenter(index);
|
||
|
var style;
|
||
|
var textAlign;
|
||
|
var name;
|
||
|
var rotation;
|
||
|
var x = 0;
|
||
|
var y = 0;
|
||
|
var margin;
|
||
|
var textStyle;
|
||
|
|
||
|
for (var i = 0; i < indicator.length; i ++) {
|
||
|
name = this.deepQuery(
|
||
|
[indicator[i], item, this.option], 'name'
|
||
|
);
|
||
|
|
||
|
if (!name.show) {
|
||
|
continue;
|
||
|
}
|
||
|
textStyle = this.deepQuery(
|
||
|
[name, item, this.option],
|
||
|
'textStyle'
|
||
|
);
|
||
|
|
||
|
style = {};
|
||
|
|
||
|
style.textFont = this.getFont(textStyle);
|
||
|
style.color = textStyle.color;
|
||
|
|
||
|
if (typeof name.formatter == 'function') {
|
||
|
style.text = name.formatter.call(this.myChart, indicator[i].text, i);
|
||
|
}
|
||
|
else if (typeof name.formatter == 'string'){
|
||
|
style.text = name.formatter.replace(
|
||
|
'{value}', indicator[i].text
|
||
|
);
|
||
|
}
|
||
|
else {
|
||
|
style.text = indicator[i].text;
|
||
|
}
|
||
|
__ecIndicator[i].text = style.text;
|
||
|
|
||
|
vector = __ecIndicator[i].vector;
|
||
|
|
||
|
if (Math.round(vector[0]) > 0) {
|
||
|
textAlign = 'left';
|
||
|
}
|
||
|
else if (Math.round(vector[0]) < 0) {
|
||
|
textAlign = 'right';
|
||
|
}
|
||
|
else {
|
||
|
textAlign = 'center';
|
||
|
}
|
||
|
|
||
|
if (name.margin == null) {
|
||
|
vector = this._mapVector(vector, center, 1.1);
|
||
|
}
|
||
|
else {
|
||
|
margin = name.margin;
|
||
|
x = vector[0] > 0 ? margin : - margin;
|
||
|
y = vector[1] > 0 ? margin : - margin;
|
||
|
|
||
|
x = vector[0] === 0 ? 0 : x;
|
||
|
y = vector[1] === 0 ? 0 : y;
|
||
|
vector = this._mapVector(vector, center, 1);
|
||
|
}
|
||
|
|
||
|
|
||
|
style.textAlign = textAlign;
|
||
|
style.x = vector[0] + x;
|
||
|
style.y = vector[1] + y;
|
||
|
|
||
|
if (name.rotate) {
|
||
|
rotation = [
|
||
|
name.rotate / 180 * Math.PI,
|
||
|
vector[0], vector[1]
|
||
|
];
|
||
|
}
|
||
|
else {
|
||
|
rotation = [0, 0, 0];
|
||
|
}
|
||
|
|
||
|
this.shapeList.push(new TextShape({
|
||
|
zlevel: this.getZlevelBase(),
|
||
|
z: this.getZBase(),
|
||
|
style : style,
|
||
|
draggable : false,
|
||
|
hoverable : false,
|
||
|
rotation : rotation
|
||
|
}));
|
||
|
}
|
||
|
},
|
||
|
|
||
|
getIndicatorText : function(polarIndex, indicatorIndex) {
|
||
|
return this.polar[polarIndex]
|
||
|
&& this.polar[polarIndex].__ecIndicator[indicatorIndex]
|
||
|
&& this.polar[polarIndex].__ecIndicator[indicatorIndex].text;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 添加一个隐形的盒子 当做drop的容器 暴露给外部的图形类使用
|
||
|
* @param {number} polar的index
|
||
|
* @return {Object} 添加的盒子图形
|
||
|
*/
|
||
|
getDropBox : function (index) {
|
||
|
var index = index || 0;
|
||
|
var item = this.polar[index];
|
||
|
var center = this.getCenter(index);
|
||
|
var __ecIndicator = item.__ecIndicator;
|
||
|
var len = __ecIndicator.length;
|
||
|
var pointList = [];
|
||
|
var vector;
|
||
|
var shape;
|
||
|
var type = item.type;
|
||
|
|
||
|
if (type == 'polygon') {
|
||
|
for (var i = 0; i < len; i ++) {
|
||
|
vector = __ecIndicator[i].vector;
|
||
|
pointList.push(this._mapVector(vector, center, 1.2));
|
||
|
}
|
||
|
shape = this._getShape(
|
||
|
pointList, 'fill', 'rgba(0,0,0,0)', '', 1
|
||
|
);
|
||
|
} else if (type == 'circle') {
|
||
|
shape = this._getCircle(
|
||
|
'', 1, 1.2, center, 'fill', 'rgba(0,0,0,0)'
|
||
|
);
|
||
|
}
|
||
|
|
||
|
return shape;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 绘制蜘蛛网的正n变形
|
||
|
*
|
||
|
* @param {Array<Object>} 指标数组
|
||
|
* @param {number} 分割线数量
|
||
|
* @param {Array<number>} 中点坐标
|
||
|
* @param {Object} 分割区域对象
|
||
|
* @param {string} 线条颜色
|
||
|
* @param {number} 线条宽度
|
||
|
*/
|
||
|
_addArea : function (
|
||
|
__ecIndicator, splitNumber, center,
|
||
|
splitArea, strokeColor, lineWidth, show
|
||
|
) {
|
||
|
var shape;
|
||
|
var scale;
|
||
|
var scale1;
|
||
|
var pointList;
|
||
|
var type = this.deepQuery(this._queryTarget, 'type');
|
||
|
|
||
|
for (var i = 0; i < splitNumber ; i ++ ) {
|
||
|
scale = (splitNumber - i) / splitNumber;
|
||
|
|
||
|
if (show) {
|
||
|
if (type == 'polygon') {
|
||
|
pointList = this._getPointList(
|
||
|
__ecIndicator, scale, center);
|
||
|
shape = this._getShape(
|
||
|
pointList, 'stroke', '', strokeColor, lineWidth
|
||
|
);
|
||
|
} else if (type == 'circle') {
|
||
|
shape = this._getCircle(
|
||
|
strokeColor, lineWidth, scale, center, 'stroke'
|
||
|
);
|
||
|
}
|
||
|
|
||
|
this.shapeList.push(shape);
|
||
|
}
|
||
|
|
||
|
if (splitArea.show) {
|
||
|
scale1 = (splitNumber - i - 1) / splitNumber;
|
||
|
this._addSplitArea(
|
||
|
__ecIndicator, splitArea, scale, scale1, center, i
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 绘制圆
|
||
|
*
|
||
|
* @param {string} strokeColor
|
||
|
* @param {number} lineWidth
|
||
|
* @param {number} scale
|
||
|
* @param {Array.<number>} center
|
||
|
* @param {string} brushType
|
||
|
* @param {string} color
|
||
|
* @return {Circle}
|
||
|
*/
|
||
|
_getCircle : function (
|
||
|
strokeColor, lineWidth, scale, center, brushType, color
|
||
|
) {
|
||
|
var radius = this._getRadius();
|
||
|
return new Circle({
|
||
|
zlevel: this.getZlevelBase(),
|
||
|
z: this.getZBase(),
|
||
|
style: {
|
||
|
x: center[0],
|
||
|
y: center[1],
|
||
|
r: radius * scale,
|
||
|
brushType: brushType,
|
||
|
strokeColor: strokeColor,
|
||
|
lineWidth: lineWidth,
|
||
|
color: color
|
||
|
},
|
||
|
hoverable : false,
|
||
|
draggable : false
|
||
|
});
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 绘制圆环
|
||
|
*
|
||
|
* @param {string} color 间隔颜色
|
||
|
* @param {number} scale0 小圆的scale
|
||
|
* @param {number} scale1 大圆的scale
|
||
|
* @param {Array.<number>} center 圆点
|
||
|
* @return {Ring}
|
||
|
*/
|
||
|
_getRing : function (color, scale0, scale1, center) {
|
||
|
var radius = this._getRadius();
|
||
|
return new Ring({
|
||
|
zlevel: this.getZlevelBase(),
|
||
|
z: this.getZBase(),
|
||
|
style : {
|
||
|
x : center[0],
|
||
|
y : center[1],
|
||
|
r : scale0 * radius,
|
||
|
r0 : scale1 * radius,
|
||
|
color : color,
|
||
|
brushType : 'fill'
|
||
|
},
|
||
|
hoverable : false,
|
||
|
draggable : false
|
||
|
});
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 获取需要绘制的多边形的点集
|
||
|
* @param {Object} serie的指标参数
|
||
|
* @param {number} 缩小的系数
|
||
|
* @param {Array<number>} 中点坐标
|
||
|
*
|
||
|
* @return {Array<Array<number>>} 返回绘制的点集
|
||
|
*/
|
||
|
_getPointList : function (__ecIndicator, scale, center) {
|
||
|
var pointList = [];
|
||
|
var len = __ecIndicator.length;
|
||
|
var vector;
|
||
|
|
||
|
for (var i = 0 ; i < len ; i ++ ) {
|
||
|
vector = __ecIndicator[i].vector;
|
||
|
|
||
|
pointList.push(this._mapVector(vector, center, scale));
|
||
|
}
|
||
|
return pointList;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 获取绘制的图形
|
||
|
* @param {Array<Array<number>>} 绘制的点集
|
||
|
* @param {string} 绘制方式 stroke | fill | both 描边 | 填充 | 描边 + 填充
|
||
|
* @param {string} 颜色
|
||
|
* @param {string} 描边颜色
|
||
|
* @param {number} 线条宽度
|
||
|
* @return {Object} 绘制的图形对象
|
||
|
*/
|
||
|
_getShape : function (
|
||
|
pointList, brushType, color, strokeColor, lineWidth
|
||
|
) {
|
||
|
return new PolygonShape({
|
||
|
zlevel: this.getZlevelBase(),
|
||
|
z: this.getZBase(),
|
||
|
style : {
|
||
|
pointList : pointList,
|
||
|
brushType : brushType,
|
||
|
color : color,
|
||
|
strokeColor : strokeColor,
|
||
|
lineWidth : lineWidth
|
||
|
},
|
||
|
hoverable : false,
|
||
|
draggable : false
|
||
|
});
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 绘制填充区域
|
||
|
*/
|
||
|
_addSplitArea : function (
|
||
|
__ecIndicator, splitArea, scale, scale1, center, colorInd
|
||
|
) {
|
||
|
var indLen = __ecIndicator.length;
|
||
|
var color;
|
||
|
var colorArr = splitArea.areaStyle.color;
|
||
|
var colorLen;
|
||
|
|
||
|
var vector;
|
||
|
var vector1;
|
||
|
var pointList = [];
|
||
|
var indLen = __ecIndicator.length;
|
||
|
var shape;
|
||
|
|
||
|
var type = this.deepQuery(this._queryTarget, 'type');
|
||
|
|
||
|
if (typeof colorArr == 'string') {
|
||
|
colorArr = [colorArr];
|
||
|
}
|
||
|
colorLen = colorArr.length;
|
||
|
color = colorArr[ colorInd % colorLen];
|
||
|
|
||
|
if (type == 'polygon') {
|
||
|
for (var i = 0; i < indLen ; i ++) {
|
||
|
pointList = [];
|
||
|
vector = __ecIndicator[i].vector;
|
||
|
vector1 = __ecIndicator[(i + 1) % indLen].vector;
|
||
|
|
||
|
pointList.push(this._mapVector(vector, center, scale));
|
||
|
pointList.push(this._mapVector(vector, center, scale1));
|
||
|
pointList.push(this._mapVector(vector1, center, scale1));
|
||
|
pointList.push(this._mapVector(vector1, center, scale));
|
||
|
|
||
|
shape = this._getShape(
|
||
|
pointList, 'fill', color, '', 1
|
||
|
);
|
||
|
this.shapeList.push(shape);
|
||
|
}
|
||
|
} else if (type == 'circle') {
|
||
|
shape = this._getRing(color, scale, scale1, center);
|
||
|
this.shapeList.push(shape);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 转换坐标
|
||
|
*
|
||
|
* @param {Array<number>} 原始坐标
|
||
|
* @param {Array<number>} 中点坐标
|
||
|
* @param {number} 缩小的倍数
|
||
|
*
|
||
|
* @return {Array<number>} 转换后的坐标
|
||
|
*/
|
||
|
_mapVector : function (vector, center, scale) {
|
||
|
return [
|
||
|
vector[0] * scale + center[0],
|
||
|
vector[1] * scale + center[1]
|
||
|
];
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 获取中心点位置 暴露给外部图形类使用
|
||
|
* @param {number} polar的index
|
||
|
*/
|
||
|
getCenter : function (index) {
|
||
|
var index = index || 0;
|
||
|
return this.parseCenter(this.zr, this.polar[index].center);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 绘制从中点出发的线
|
||
|
*
|
||
|
* @param {Array<Object>} 指标对象
|
||
|
* @param {Array<number>} 中点坐标
|
||
|
* @param {string} 线条颜色
|
||
|
* @param {number} 线条宽度
|
||
|
* @param {string} 线条绘制类型
|
||
|
* solid | dotted | dashed 实线 | 点线 | 虚线
|
||
|
*/
|
||
|
_addLine : function (
|
||
|
__ecIndicator, center, axisLine
|
||
|
) {
|
||
|
var indLen = __ecIndicator.length;
|
||
|
var line;
|
||
|
var vector;
|
||
|
var lineStyle = axisLine.lineStyle;
|
||
|
var strokeColor = lineStyle.color;
|
||
|
var lineWidth = lineStyle.width;
|
||
|
var lineType = lineStyle.type;
|
||
|
|
||
|
for (var i = 0; i < indLen ; i ++ ) {
|
||
|
vector = __ecIndicator[i].vector;
|
||
|
line = this._getLine(
|
||
|
center[0], center[1],
|
||
|
vector[0] + center[0],
|
||
|
vector[1] + center[1],
|
||
|
strokeColor, lineWidth, lineType
|
||
|
);
|
||
|
this.shapeList.push(line);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 获取线条对象
|
||
|
* @param {number} 出发点横坐标
|
||
|
* @param {number} 出发点纵坐标
|
||
|
* @param {number} 终点横坐标
|
||
|
* @param {number} 终点纵坐标
|
||
|
* @param {string} 线条颜色
|
||
|
* @param {number} 线条宽度
|
||
|
* @param {string} 线条类型
|
||
|
*
|
||
|
* @return {Object} 线条对象
|
||
|
*/
|
||
|
_getLine : function (
|
||
|
xStart, yStart, xEnd, yEnd, strokeColor, lineWidth, lineType
|
||
|
) {
|
||
|
return new LineShape({
|
||
|
zlevel: this.getZlevelBase(),
|
||
|
z: this.getZBase(),
|
||
|
style : {
|
||
|
xStart : xStart,
|
||
|
yStart : yStart,
|
||
|
xEnd : xEnd,
|
||
|
yEnd : yEnd,
|
||
|
strokeColor : strokeColor,
|
||
|
lineWidth : lineWidth,
|
||
|
lineType : lineType
|
||
|
},
|
||
|
hoverable : false
|
||
|
});
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 调整指标的值,当indicator中存在max时设置为固定值
|
||
|
* @param {number} polar的index
|
||
|
*/
|
||
|
_adjustIndicatorValue : function (index) {
|
||
|
var item = this.polar[index];
|
||
|
var indicator = this.deepQuery(this._queryTarget, 'indicator');
|
||
|
var len = indicator.length;
|
||
|
var __ecIndicator = item.__ecIndicator;
|
||
|
var max;
|
||
|
var min;
|
||
|
var data = this._getSeriesData(index);
|
||
|
|
||
|
var boundaryGap = item.boundaryGap;
|
||
|
var splitNumber = item.splitNumber;
|
||
|
var scale = item.scale;
|
||
|
var opts;
|
||
|
|
||
|
var smartSteps = require('../util/smartSteps');
|
||
|
for (var i = 0; i < len ; i ++ ) {
|
||
|
if (typeof indicator[i].max == 'number') {
|
||
|
max = indicator[i].max;
|
||
|
min = indicator[i].min || 0;
|
||
|
opts = {
|
||
|
max: max,
|
||
|
min: min
|
||
|
};
|
||
|
}
|
||
|
else {
|
||
|
var value = this._findValue(
|
||
|
data, i, splitNumber, boundaryGap
|
||
|
);
|
||
|
min = value.min;
|
||
|
max = value.max;
|
||
|
}
|
||
|
// 非scale下双正,修正最小值为0
|
||
|
if (!scale && min >= 0 && max >= 0) {
|
||
|
min = 0;
|
||
|
}
|
||
|
// 非scale下双负,修正最大值为0
|
||
|
if (!scale && min <= 0 && max <= 0) {
|
||
|
max = 0;
|
||
|
}
|
||
|
var stepOpt = smartSteps(min, max, splitNumber, opts);
|
||
|
|
||
|
__ecIndicator[i].value = {
|
||
|
min: stepOpt.min,
|
||
|
max: stepOpt.max,
|
||
|
step: stepOpt.step
|
||
|
};
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 将series中的数据拿出来,如果没有polarIndex属性,默认为零
|
||
|
* @param {number} polar 的index
|
||
|
* @param {Array<Object>} 需要处理的数据
|
||
|
*/
|
||
|
_getSeriesData : function (index) {
|
||
|
var data = [];
|
||
|
var serie;
|
||
|
var serieData;
|
||
|
var legend = this.component.legend;
|
||
|
var polarIndex;
|
||
|
|
||
|
for (var i = 0; i < this.series.length; i ++) {
|
||
|
serie = this.series[i];
|
||
|
if (serie.type != ecConfig.CHART_TYPE_RADAR) {
|
||
|
continue;
|
||
|
}
|
||
|
serieData = serie.data || [];
|
||
|
for (var j = 0; j < serieData.length; j ++) {
|
||
|
polarIndex = this.deepQuery(
|
||
|
[serieData[j], serie, this.option], 'polarIndex'
|
||
|
) || 0;
|
||
|
if (polarIndex == index
|
||
|
&& (!legend || legend.isSelected(serieData[j].name))
|
||
|
) {
|
||
|
data.push(serieData[j]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return data;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 查找指标合适的值
|
||
|
*
|
||
|
* 如果只有一组数据以数据中的最大值作为最大值 0为最小值
|
||
|
* 如果是多组,使用同一维度的进行比较 选出最大值最小值
|
||
|
* 对它们进行处理
|
||
|
* @param {Object} serie 的 data
|
||
|
* @param {number} index 指标的序号
|
||
|
* @param {number} splitNumber 分段格式
|
||
|
* * @param {boolean} boundaryGap 两端留白
|
||
|
*/
|
||
|
_findValue : function (data, index, splitNumber, boundaryGap) {
|
||
|
var max;
|
||
|
var min;
|
||
|
var one;
|
||
|
|
||
|
if (!data || data.length === 0) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
function _compare(item) {
|
||
|
(item > max || max === undefined) && (max = item);
|
||
|
(item < min || min === undefined) && (min = item);
|
||
|
}
|
||
|
|
||
|
if (data.length == 1) {
|
||
|
min = 0;
|
||
|
}
|
||
|
if (data.length != 1) {
|
||
|
for (var i = 0; i < data.length; i ++) {
|
||
|
_compare(this.getDataFromOption(data[i].value[index]));
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
one = data[0];
|
||
|
for (var i = 0; i < one.value.length; i ++) {
|
||
|
_compare(this.getDataFromOption(one.value[i]));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var gap = Math.abs(max - min);
|
||
|
min = min - Math.abs(gap * boundaryGap[0]);
|
||
|
max = max + Math.abs(gap * boundaryGap[1]);
|
||
|
if (min === max) {
|
||
|
if (max === 0) {
|
||
|
// 修复全0数据
|
||
|
max = 1;
|
||
|
}
|
||
|
// 修复最大值==最小值时数据整形
|
||
|
else if (max > 0) {
|
||
|
min = max / splitNumber;
|
||
|
}
|
||
|
else { // max < 0
|
||
|
max = max / splitNumber;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
max : max,
|
||
|
min : min
|
||
|
};
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 获取每个指标上某个value对应的坐标
|
||
|
* @param {number} polarIndex
|
||
|
* @param {number} indicatorIndex
|
||
|
* @param {number} value
|
||
|
* @return {Array<number>} 对应坐标
|
||
|
*/
|
||
|
getVector : function (polarIndex, indicatorIndex, value) {
|
||
|
polarIndex = polarIndex || 0;
|
||
|
indicatorIndex = indicatorIndex || 0;
|
||
|
var __ecIndicator = this.polar[polarIndex].__ecIndicator;
|
||
|
|
||
|
if (indicatorIndex >= __ecIndicator.length) {
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
var indicator = this.polar[polarIndex].__ecIndicator[indicatorIndex];
|
||
|
var center = this.getCenter(polarIndex);
|
||
|
var vector = indicator.vector;
|
||
|
var max = indicator.value.max;
|
||
|
var min = indicator.value.min;
|
||
|
var alpha;
|
||
|
|
||
|
if (typeof value == 'undefined') {
|
||
|
return center;
|
||
|
}
|
||
|
|
||
|
switch (value) {
|
||
|
case 'min' :
|
||
|
value = min;
|
||
|
break;
|
||
|
case 'max' :
|
||
|
value = max;
|
||
|
break;
|
||
|
case 'center' :
|
||
|
value = (max + min) / 2;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (max != min) {
|
||
|
alpha = (value - min) / (max - min);
|
||
|
}
|
||
|
else {
|
||
|
alpha = 0.5;
|
||
|
}
|
||
|
|
||
|
return this._mapVector(vector, center, alpha);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 判断一个点是否在网内
|
||
|
* @param {Array<number>} 坐标
|
||
|
* @return {number} 返回polarindex 返回-1表示不在任何polar
|
||
|
*/
|
||
|
isInside : function (vector) {
|
||
|
var polar = this.getNearestIndex(vector);
|
||
|
|
||
|
if (polar) {
|
||
|
return polar.polarIndex;
|
||
|
}
|
||
|
return -1;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 如果一个点在网内,返回离它最近的数据轴的index
|
||
|
* @param {Array<number>} 坐标
|
||
|
* @return {Object} | false
|
||
|
* polarIndex
|
||
|
* valueIndex
|
||
|
*/
|
||
|
getNearestIndex : function (vector) {
|
||
|
var item;
|
||
|
var center;
|
||
|
var radius;
|
||
|
var polarVector;
|
||
|
var startAngle;
|
||
|
var indicator;
|
||
|
var len;
|
||
|
var angle;
|
||
|
var finalAngle;
|
||
|
for (var i = 0 ; i < this.polar.length; i ++) {
|
||
|
item = this.polar[i];
|
||
|
center = this.getCenter(i);
|
||
|
if (vector[0] == center[0] && vector[1] == center[1]) {
|
||
|
return {
|
||
|
polarIndex : i,
|
||
|
valueIndex : 0
|
||
|
};
|
||
|
}
|
||
|
radius = this._getRadius();
|
||
|
startAngle = item.startAngle;
|
||
|
indicator = item.indicator;
|
||
|
len = indicator.length;
|
||
|
angle = 2 * Math.PI / len;
|
||
|
// 注意y轴的翻转
|
||
|
polarVector = ecCoordinates.cartesian2polar(
|
||
|
vector[0] - center[0], center[1] - vector[1]
|
||
|
);
|
||
|
if (vector[0] - center[0] < 0) {
|
||
|
polarVector[1] += Math.PI;
|
||
|
}
|
||
|
if (polarVector[1] < 0) {
|
||
|
polarVector[1] += 2 * Math.PI;
|
||
|
}
|
||
|
|
||
|
|
||
|
// 减去startAngle的偏移量 再加2PI变成正数
|
||
|
finalAngle = polarVector[1] -
|
||
|
startAngle / 180 * Math.PI + Math.PI * 2;
|
||
|
|
||
|
if (Math.abs(Math.cos(finalAngle % (angle / 2))) * radius
|
||
|
> polarVector[0])
|
||
|
{
|
||
|
return {
|
||
|
polarIndex : i,
|
||
|
valueIndex : Math.floor(
|
||
|
(finalAngle + angle / 2 ) / angle
|
||
|
) % len
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 获取指标信息
|
||
|
* @param {number} polarIndex
|
||
|
* @return {Array<Object>} indicator
|
||
|
*/
|
||
|
getIndicator : function (index) {
|
||
|
var index = index || 0;
|
||
|
return this.polar[index].indicator;
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 刷新
|
||
|
*/
|
||
|
refresh : function (newOption) {
|
||
|
if (newOption) {
|
||
|
this.option = newOption;
|
||
|
this.polar = this.option.polar;
|
||
|
this.series = this.option.series;
|
||
|
}
|
||
|
this.clear();
|
||
|
this._buildShape();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
zrUtil.inherits(Polar, Base);
|
||
|
|
||
|
require('../component').define('polar', Polar);
|
||
|
|
||
|
return Polar;
|
||
|
});
|