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.
949 lines
37 KiB
949 lines
37 KiB
4 years ago
|
/**
|
||
|
* echarts组件: 数值轴
|
||
|
*
|
||
|
* @desc echarts基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据统计图表。
|
||
|
* @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
|
||
|
*
|
||
|
*/
|
||
|
define(function (require) {
|
||
|
var Base = require('./base');
|
||
|
|
||
|
// 图形依赖
|
||
|
var TextShape = require('zrender/shape/Text');
|
||
|
var LineShape = require('zrender/shape/Line');
|
||
|
var RectangleShape = require('zrender/shape/Rectangle');
|
||
|
|
||
|
var ecConfig = require('../config');
|
||
|
// 数值型坐标轴默认参数
|
||
|
ecConfig.valueAxis = {
|
||
|
zlevel: 0, // 一级层叠
|
||
|
z: 0, // 二级层叠
|
||
|
show: true,
|
||
|
position: 'left', // 位置
|
||
|
name: '', // 坐标轴名字,默认为空
|
||
|
nameLocation: 'end', // 坐标轴名字位置,支持'start' | 'end'
|
||
|
nameTextStyle: {}, // 坐标轴文字样式,默认取全局样式
|
||
|
boundaryGap: [0, 0], // 数值起始和结束两端空白策略
|
||
|
// min: null, // 最小值
|
||
|
// max: null, // 最大值
|
||
|
// scale: false, // 脱离0值比例,放大聚焦到最终_min,_max区间
|
||
|
// splitNumber: 5, // 分割段数,默认为5
|
||
|
axisLine: { // 坐标轴线
|
||
|
show: true, // 默认显示,属性show控制显示与否
|
||
|
onZero: true,
|
||
|
lineStyle: { // 属性lineStyle控制线条样式
|
||
|
color: '#48b',
|
||
|
width: 2,
|
||
|
type: 'solid'
|
||
|
}
|
||
|
},
|
||
|
axisTick: { // 坐标轴小标记
|
||
|
show: false, // 属性show控制显示与否,默认不显示
|
||
|
inside: false, // 控制小标记是否在grid里
|
||
|
length :5, // 属性length控制线长
|
||
|
lineStyle: { // 属性lineStyle控制线条样式
|
||
|
color: '#333',
|
||
|
width: 1
|
||
|
}
|
||
|
},
|
||
|
axisLabel: { // 坐标轴文本标签,详见axis.axisLabel
|
||
|
show: true,
|
||
|
rotate: 0,
|
||
|
margin: 8,
|
||
|
// clickable: false,
|
||
|
// formatter: null,
|
||
|
textStyle: { // 其余属性默认使用全局文本样式,详见TEXTSTYLE
|
||
|
color: '#333'
|
||
|
}
|
||
|
},
|
||
|
splitLine: { // 分隔线
|
||
|
show: true, // 默认显示,属性show控制显示与否
|
||
|
lineStyle: { // 属性lineStyle(详见lineStyle)控制线条样式
|
||
|
color: ['#ccc'],
|
||
|
width: 1,
|
||
|
type: 'solid'
|
||
|
}
|
||
|
},
|
||
|
splitArea: { // 分隔区域
|
||
|
show: false, // 默认不显示,属性show控制显示与否
|
||
|
areaStyle: { // 属性areaStyle(详见areaStyle)控制区域样式
|
||
|
color: ['rgba(250,250,250,0.3)','rgba(200,200,200,0.3)']
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var ecDate = require('../util/date');
|
||
|
var zrUtil = require('zrender/tool/util');
|
||
|
|
||
|
/**
|
||
|
* 构造函数
|
||
|
* @param {Object} messageCenter echart消息中心
|
||
|
* @param {ZRender} zr zrender实例
|
||
|
* @param {Object} option 类目轴参数
|
||
|
* @param {Object} component 组件
|
||
|
* @param {Array} series 数据对象
|
||
|
*/
|
||
|
function ValueAxis(ecTheme, messageCenter, zr, option, myChart, axisBase, series) {
|
||
|
if (!series || series.length === 0) {
|
||
|
console.err('option.series.length == 0.');
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Base.call(this, ecTheme, messageCenter, zr, option, myChart);
|
||
|
|
||
|
this.series = series;
|
||
|
this.grid = this.component.grid;
|
||
|
|
||
|
for (var method in axisBase) {
|
||
|
this[method] = axisBase[method];
|
||
|
}
|
||
|
|
||
|
this.refresh(option, series);
|
||
|
}
|
||
|
|
||
|
ValueAxis.prototype = {
|
||
|
type: ecConfig.COMPONENT_TYPE_AXIS_VALUE,
|
||
|
|
||
|
_buildShape: function () {
|
||
|
this._hasData = false;
|
||
|
this._calculateValue();
|
||
|
if (!this._hasData || !this.option.show) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
this.option.splitArea.show && this._buildSplitArea();
|
||
|
this.option.splitLine.show && this._buildSplitLine();
|
||
|
this.option.axisLine.show && this._buildAxisLine();
|
||
|
this.option.axisTick.show && this._buildAxisTick();
|
||
|
this.option.axisLabel.show && this._buildAxisLabel();
|
||
|
|
||
|
for (var i = 0, l = this.shapeList.length; i < l; i++) {
|
||
|
this.zr.addShape(this.shapeList[i]);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// 小标记
|
||
|
_buildAxisTick: function () {
|
||
|
var axShape;
|
||
|
var data = this._valueList;
|
||
|
var dataLength = this._valueList.length;
|
||
|
var tickOption = this.option.axisTick;
|
||
|
var length = tickOption.length;
|
||
|
var color = tickOption.lineStyle.color;
|
||
|
var lineWidth = tickOption.lineStyle.width;
|
||
|
|
||
|
if (this.isHorizontal()) {
|
||
|
// 横向
|
||
|
var yPosition = this.option.position === 'bottom'
|
||
|
? (tickOption.inside
|
||
|
? (this.grid.getYend() - length - 1) : (this.grid.getYend()) + 1)
|
||
|
: (tickOption.inside
|
||
|
? (this.grid.getY() + 1) : (this.grid.getY() - length - 1));
|
||
|
var x;
|
||
|
for (var i = 0; i < dataLength; i++) {
|
||
|
// 亚像素优化
|
||
|
x = this.subPixelOptimize(this.getCoord(data[i]), lineWidth);
|
||
|
axShape = {
|
||
|
_axisShape: 'axisTick',
|
||
|
zlevel: this.getZlevelBase(),
|
||
|
z: this.getZBase(),
|
||
|
hoverable: false,
|
||
|
style: {
|
||
|
xStart: x,
|
||
|
yStart: yPosition,
|
||
|
xEnd: x,
|
||
|
yEnd: yPosition + length,
|
||
|
strokeColor: color,
|
||
|
lineWidth: lineWidth
|
||
|
}
|
||
|
};
|
||
|
this.shapeList.push(new LineShape(axShape));
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// 纵向
|
||
|
var xPosition = this.option.position === 'left'
|
||
|
? (tickOption.inside
|
||
|
? (this.grid.getX() + 1) : (this.grid.getX() - length - 1))
|
||
|
: (tickOption.inside
|
||
|
? (this.grid.getXend() - length - 1) : (this.grid.getXend() + 1));
|
||
|
|
||
|
var y;
|
||
|
for (var i = 0; i < dataLength; i++) {
|
||
|
// 亚像素优化
|
||
|
y = this.subPixelOptimize(this.getCoord(data[i]), lineWidth);
|
||
|
axShape = {
|
||
|
_axisShape: 'axisTick',
|
||
|
zlevel: this.getZlevelBase(),
|
||
|
z: this.getZBase(),
|
||
|
hoverable: false,
|
||
|
style: {
|
||
|
xStart: xPosition,
|
||
|
yStart: y,
|
||
|
xEnd: xPosition + length,
|
||
|
yEnd: y,
|
||
|
strokeColor: color,
|
||
|
lineWidth: lineWidth
|
||
|
}
|
||
|
};
|
||
|
this.shapeList.push(new LineShape(axShape));
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// 坐标轴文本
|
||
|
_buildAxisLabel: function () {
|
||
|
var axShape;
|
||
|
var data = this._valueList;
|
||
|
var dataLength = this._valueList.length;
|
||
|
var rotate = this.option.axisLabel.rotate;
|
||
|
var margin = this.option.axisLabel.margin;
|
||
|
var clickable = this.option.axisLabel.clickable;
|
||
|
var textStyle = this.option.axisLabel.textStyle;
|
||
|
|
||
|
if (this.isHorizontal()) {
|
||
|
// 横向
|
||
|
var yPosition;
|
||
|
var baseLine;
|
||
|
if (this.option.position === 'bottom') {
|
||
|
yPosition = this.grid.getYend() + margin;
|
||
|
baseLine = 'top';
|
||
|
}
|
||
|
else {
|
||
|
yPosition = this.grid.getY() - margin;
|
||
|
baseLine = 'bottom';
|
||
|
}
|
||
|
|
||
|
for (var i = 0; i < dataLength; i++) {
|
||
|
axShape = {
|
||
|
zlevel: this.getZlevelBase(),
|
||
|
z: this.getZBase() +3,
|
||
|
hoverable: false,
|
||
|
style: {
|
||
|
x: this.getCoord(data[i]),
|
||
|
y: yPosition,
|
||
|
color: typeof textStyle.color === 'function'
|
||
|
? textStyle.color(data[i]) : textStyle.color,
|
||
|
text: this._valueLabel[i],
|
||
|
textFont: this.getFont(textStyle),
|
||
|
textAlign: textStyle.align || 'center',
|
||
|
textBaseline: textStyle.baseline || baseLine
|
||
|
}
|
||
|
};
|
||
|
if (rotate) {
|
||
|
axShape.style.textAlign = rotate > 0
|
||
|
? (this.option.position === 'bottom'
|
||
|
? 'right' : 'left')
|
||
|
: (this.option.position === 'bottom'
|
||
|
? 'left' : 'right');
|
||
|
axShape.rotation = [
|
||
|
rotate * Math.PI / 180,
|
||
|
axShape.style.x,
|
||
|
axShape.style.y
|
||
|
];
|
||
|
}
|
||
|
this.shapeList.push(new TextShape(
|
||
|
this._axisLabelClickable(clickable, axShape)
|
||
|
));
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// 纵向
|
||
|
var xPosition;
|
||
|
var align;
|
||
|
if (this.option.position === 'left') {
|
||
|
xPosition = this.grid.getX() - margin;
|
||
|
align = 'right';
|
||
|
}
|
||
|
else {
|
||
|
xPosition = this.grid.getXend() + margin;
|
||
|
align = 'left';
|
||
|
}
|
||
|
|
||
|
for (var i = 0; i < dataLength; i++) {
|
||
|
axShape = {
|
||
|
zlevel: this.getZlevelBase(),
|
||
|
z: this.getZBase() + 3,
|
||
|
hoverable: false,
|
||
|
style: {
|
||
|
x: xPosition,
|
||
|
y: this.getCoord(data[i]),
|
||
|
color: typeof textStyle.color === 'function'
|
||
|
? textStyle.color(data[i]) : textStyle.color,
|
||
|
text: this._valueLabel[i],
|
||
|
textFont: this.getFont(textStyle),
|
||
|
textAlign: textStyle.align || align,
|
||
|
textBaseline: textStyle.baseline
|
||
|
|| (
|
||
|
(i === 0 && this.option.name !== '')
|
||
|
? 'bottom'
|
||
|
: (i === dataLength - 1 && this.option.name !== '') ? 'top' : 'middle'
|
||
|
)
|
||
|
}
|
||
|
};
|
||
|
|
||
|
if (rotate) {
|
||
|
axShape.rotation = [
|
||
|
rotate * Math.PI / 180,
|
||
|
axShape.style.x,
|
||
|
axShape.style.y
|
||
|
];
|
||
|
}
|
||
|
this.shapeList.push(new TextShape(
|
||
|
this._axisLabelClickable(clickable, axShape)
|
||
|
));
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_buildSplitLine: function () {
|
||
|
var axShape;
|
||
|
var data = this._valueList;
|
||
|
var dataLength = this._valueList.length;
|
||
|
var sLineOption = this.option.splitLine;
|
||
|
var lineType = sLineOption.lineStyle.type;
|
||
|
var lineWidth = sLineOption.lineStyle.width;
|
||
|
var color = sLineOption.lineStyle.color;
|
||
|
color = color instanceof Array ? color : [color];
|
||
|
var colorLength = color.length;
|
||
|
|
||
|
if (this.isHorizontal()) {
|
||
|
// 横向
|
||
|
var sy = this.grid.getY();
|
||
|
var ey = this.grid.getYend();
|
||
|
var x;
|
||
|
|
||
|
for (var i = 0; i < dataLength; i++) {
|
||
|
// 亚像素优化
|
||
|
x = this.subPixelOptimize(this.getCoord(data[i]), lineWidth);
|
||
|
axShape = {
|
||
|
zlevel: this.getZlevelBase(),
|
||
|
z: this.getZBase(),
|
||
|
hoverable: false,
|
||
|
style: {
|
||
|
xStart: x,
|
||
|
yStart: sy,
|
||
|
xEnd: x,
|
||
|
yEnd: ey,
|
||
|
strokeColor: color[i % colorLength],
|
||
|
lineType: lineType,
|
||
|
lineWidth: lineWidth
|
||
|
}
|
||
|
};
|
||
|
this.shapeList.push(new LineShape(axShape));
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
// 纵向
|
||
|
var sx = this.grid.getX();
|
||
|
var ex = this.grid.getXend();
|
||
|
var y;
|
||
|
|
||
|
for (var i = 0; i < dataLength; i++) {
|
||
|
// 亚像素优化
|
||
|
y = this.subPixelOptimize(this.getCoord(data[i]), lineWidth);
|
||
|
axShape = {
|
||
|
zlevel: this.getZlevelBase(),
|
||
|
z: this.getZBase(),
|
||
|
hoverable: false,
|
||
|
style: {
|
||
|
xStart: sx,
|
||
|
yStart: y,
|
||
|
xEnd: ex,
|
||
|
yEnd: y,
|
||
|
strokeColor: color[i % colorLength],
|
||
|
lineType: lineType,
|
||
|
lineWidth: lineWidth
|
||
|
}
|
||
|
};
|
||
|
this.shapeList.push(new LineShape(axShape));
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_buildSplitArea: function () {
|
||
|
var axShape;
|
||
|
var color = this.option.splitArea.areaStyle.color;
|
||
|
|
||
|
if (!(color instanceof Array)) {
|
||
|
// 非数组一律认为是单一颜色的字符串,单一颜色则用一个背景,颜色错误不负责啊!!!
|
||
|
axShape = {
|
||
|
zlevel: this.getZlevelBase(),
|
||
|
z: this.getZBase(),
|
||
|
hoverable: false,
|
||
|
style: {
|
||
|
x: this.grid.getX(),
|
||
|
y: this.grid.getY(),
|
||
|
width: this.grid.getWidth(),
|
||
|
height: this.grid.getHeight(),
|
||
|
color: color
|
||
|
// type: this.option.splitArea.areaStyle.type,
|
||
|
}
|
||
|
};
|
||
|
this.shapeList.push(new RectangleShape(axShape));
|
||
|
}
|
||
|
else {
|
||
|
// 多颜色
|
||
|
var colorLength = color.length;
|
||
|
var data = this._valueList;
|
||
|
var dataLength = this._valueList.length;
|
||
|
|
||
|
if (this.isHorizontal()) {
|
||
|
// 横向
|
||
|
var y = this.grid.getY();
|
||
|
var height = this.grid.getHeight();
|
||
|
var lastX = this.grid.getX();
|
||
|
var curX;
|
||
|
|
||
|
for (var i = 0; i <= dataLength; i++) {
|
||
|
curX = i < dataLength
|
||
|
? this.getCoord(data[i])
|
||
|
: this.grid.getXend();
|
||
|
axShape = {
|
||
|
zlevel: this.getZlevelBase(),
|
||
|
z: this.getZBase(),
|
||
|
hoverable: false,
|
||
|
style: {
|
||
|
x: lastX,
|
||
|
y: y,
|
||
|
width: curX - lastX,
|
||
|
height: height,
|
||
|
color: color[i % colorLength]
|
||
|
// type: this.option.splitArea.areaStyle.type,
|
||
|
}
|
||
|
};
|
||
|
this.shapeList.push(new RectangleShape(axShape));
|
||
|
lastX = curX;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// 纵向
|
||
|
var x = this.grid.getX();
|
||
|
var width = this.grid.getWidth();
|
||
|
var lastYend = this.grid.getYend();
|
||
|
var curY;
|
||
|
|
||
|
for (var i = 0; i <= dataLength; i++) {
|
||
|
curY = i < dataLength
|
||
|
? this.getCoord(data[i])
|
||
|
: this.grid.getY();
|
||
|
axShape = {
|
||
|
zlevel: this.getZlevelBase(),
|
||
|
z: this.getZBase(),
|
||
|
hoverable: false,
|
||
|
style: {
|
||
|
x: x,
|
||
|
y: curY,
|
||
|
width: width,
|
||
|
height: lastYend - curY,
|
||
|
color: color[i % colorLength]
|
||
|
// type: this.option.splitArea.areaStyle.type
|
||
|
}
|
||
|
};
|
||
|
this.shapeList.push(new RectangleShape(axShape));
|
||
|
lastYend = curY;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 极值计算
|
||
|
*/
|
||
|
_calculateValue: function () {
|
||
|
if (isNaN(this.option.min - 0) || isNaN(this.option.max - 0)) {
|
||
|
// 有一个没指定都得算
|
||
|
// 数据整形
|
||
|
var data = {}; // 整形后数据抽取
|
||
|
var xIdx;
|
||
|
var yIdx;
|
||
|
var legend = this.component.legend;
|
||
|
for (var i = 0, l = this.series.length; i < l; i++) {
|
||
|
if (this.series[i].type != ecConfig.CHART_TYPE_LINE
|
||
|
&& this.series[i].type != ecConfig.CHART_TYPE_BAR
|
||
|
&& this.series[i].type != ecConfig.CHART_TYPE_SCATTER
|
||
|
&& this.series[i].type != ecConfig.CHART_TYPE_K
|
||
|
&& this.series[i].type != ecConfig.CHART_TYPE_EVENTRIVER
|
||
|
) {
|
||
|
// 非坐标轴支持的不算极值
|
||
|
continue;
|
||
|
}
|
||
|
// 请允许我写开,跟上面一个不是一样东西
|
||
|
if (legend && !legend.isSelected(this.series[i].name)){
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// 不指定默认为第一轴线
|
||
|
xIdx = this.series[i].xAxisIndex || 0;
|
||
|
yIdx = this.series[i].yAxisIndex || 0;
|
||
|
if ((this.option.xAxisIndex != xIdx)
|
||
|
&& (this.option.yAxisIndex != yIdx)
|
||
|
) {
|
||
|
// 不是自己的数据不计算极值
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
this._calculSum(data, i);
|
||
|
}
|
||
|
|
||
|
// 找极值
|
||
|
var oriData; // 原始数据
|
||
|
for (var i in data){
|
||
|
oriData = data[i];
|
||
|
for (var j = 0, k = oriData.length; j < k; j++) {
|
||
|
if (!isNaN(oriData[j])){
|
||
|
this._hasData = true;
|
||
|
this._min = oriData[j];
|
||
|
this._max = oriData[j];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (this._hasData) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
for (var i in data){
|
||
|
oriData = data[i];
|
||
|
for (var j = 0, k = oriData.length; j < k; j++) {
|
||
|
if (!isNaN(oriData[j])){
|
||
|
this._min = Math.min(this._min, oriData[j]);
|
||
|
this._max = Math.max(this._max, oriData[j]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// console.log(this._min,this._max,'vvvvv111111',this.option.type)
|
||
|
// log情况暂时禁用boundaryGap。
|
||
|
var boundaryGap = this.option.type !== 'log' ? this.option.boundaryGap : [0, 0];
|
||
|
var gap = Math.abs(this._max - this._min);
|
||
|
this._min = isNaN(this.option.min - 0)
|
||
|
? (this._min - Math.abs(gap * boundaryGap[0]))
|
||
|
: (this.option.min - 0); // 指定min忽略boundaryGay[0]
|
||
|
|
||
|
this._max = isNaN(this.option.max - 0)
|
||
|
? (this._max + Math.abs(gap * boundaryGap[1]))
|
||
|
: (this.option.max - 0); // 指定max忽略boundaryGay[1]
|
||
|
if (this._min === this._max) {
|
||
|
if (this._max === 0) {
|
||
|
// 修复全0数据
|
||
|
this._max = 1;
|
||
|
}
|
||
|
// 修复最大值==最小值时数据整形
|
||
|
else if (this._max > 0) {
|
||
|
this._min = this._max / this.option.splitNumber != null ? this.option.splitNumber : 5;
|
||
|
}
|
||
|
else { // this._max < 0
|
||
|
this._max = this._max / this.option.splitNumber != null ? this.option.splitNumber : 5;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (this.option.type === 'time') {
|
||
|
this._reformTimeValue();
|
||
|
}
|
||
|
else if (this.option.type === 'log') {
|
||
|
this._reformLogValue();
|
||
|
}
|
||
|
else {
|
||
|
this._reformValue(this.option.scale);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
this._hasData = true;
|
||
|
// 用户指定min max就不多管闲事了
|
||
|
this._min = this.option.min - 0; // 指定min忽略boundaryGay[0]
|
||
|
this._max = this.option.max - 0; // 指定max忽略boundaryGay[1]
|
||
|
|
||
|
if (this.option.type === 'time') {
|
||
|
this._reformTimeValue();
|
||
|
}
|
||
|
else if (this.option.type === 'log') {
|
||
|
this._reformLogValue();
|
||
|
}
|
||
|
else {
|
||
|
this._customerValue();
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 内部使用,计算某系列下的堆叠和
|
||
|
*/
|
||
|
_calculSum: function (data, i) {
|
||
|
var key = this.series[i].name || 'kener';
|
||
|
var value;
|
||
|
var oriData;
|
||
|
if (!this.series[i].stack) {
|
||
|
data[key] = data[key] || [];
|
||
|
if (this.series[i].type != ecConfig.CHART_TYPE_EVENTRIVER) {
|
||
|
oriData = this.series[i].data;
|
||
|
for (var j = 0, k = oriData.length; j < k; j++) {
|
||
|
value = this.getDataFromOption(oriData[j]);
|
||
|
if (this.series[i].type === ecConfig.CHART_TYPE_K) {
|
||
|
data[key].push(value[0]);
|
||
|
data[key].push(value[1]);
|
||
|
data[key].push(value[2]);
|
||
|
data[key].push(value[3]);
|
||
|
}
|
||
|
else if (value instanceof Array) {
|
||
|
// scatter 、 不等距 line bar
|
||
|
if (this.option.xAxisIndex != -1) {
|
||
|
data[key].push(
|
||
|
this.option.type != 'time'
|
||
|
? value[0] : ecDate.getNewDate(value[0])
|
||
|
);
|
||
|
}
|
||
|
if (this.option.yAxisIndex != -1) {
|
||
|
data[key].push(
|
||
|
this.option.type != 'time'
|
||
|
? value[1] : ecDate.getNewDate(value[1])
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
data[key].push(value);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// eventRiver
|
||
|
oriData = this.series[i].data;
|
||
|
for (var j = 0, k = oriData.length; j < k; j++) {
|
||
|
var evolution = oriData[j].evolution;
|
||
|
for (var m = 0, n = evolution.length; m < n; m++) {
|
||
|
data[key].push(ecDate.getNewDate(evolution[m].time));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// 堆积数据,需要区分正负向堆积
|
||
|
var keyP = '__Magic_Key_Positive__' + this.series[i].stack;
|
||
|
var keyN = '__Magic_Key_Negative__' + this.series[i].stack;
|
||
|
data[keyP] = data[keyP] || [];
|
||
|
data[keyN] = data[keyN] || [];
|
||
|
data[key] = data[key] || []; // scale下还需要记录每一个量
|
||
|
oriData = this.series[i].data;
|
||
|
for (var j = 0, k = oriData.length; j < k; j++) {
|
||
|
value = this.getDataFromOption(oriData[j]);
|
||
|
if (value === '-') {
|
||
|
continue;
|
||
|
}
|
||
|
value = value - 0;
|
||
|
if (value >= 0) {
|
||
|
if (data[keyP][j] != null) {
|
||
|
data[keyP][j] += value;
|
||
|
}
|
||
|
else {
|
||
|
data[keyP][j] = value;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (data[keyN][j] != null) {
|
||
|
data[keyN][j] += value;
|
||
|
}
|
||
|
else {
|
||
|
data[keyN][j] = value;
|
||
|
}
|
||
|
}
|
||
|
if (this.option.scale) {
|
||
|
data[key].push(value);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 找到原始数据的极值后根据选项整形最终 this._min / this._max / this._valueList
|
||
|
* 如果你不知道这个“整形”的用义,请不要试图去理解和修改这个方法!找我也没用,我相信我已经记不起来!
|
||
|
* 如果你有更简洁的数学推导欢迎重写,后果自负~
|
||
|
*
|
||
|
* by kener.linfeng@gmail.com 2013-1-8
|
||
|
* --------
|
||
|
* 感谢谢世威(https://github.com/i6ma),终于有人改这个方法了
|
||
|
* by Kener 2014-11-6
|
||
|
*/
|
||
|
_reformValue: function (scale) {
|
||
|
var smartSteps = require('../util/smartSteps');
|
||
|
var splitNumber = this.option.splitNumber;
|
||
|
|
||
|
// 非scale下双正,修正最小值为0
|
||
|
if (!scale && this._min >= 0 && this._max >= 0) {
|
||
|
this._min = 0;
|
||
|
}
|
||
|
// 非scale下双负,修正最大值为0
|
||
|
if (!scale && this._min <= 0 && this._max <= 0) {
|
||
|
this._max = 0;
|
||
|
}
|
||
|
|
||
|
var stepOpt = smartSteps(this._min, this._max, splitNumber);
|
||
|
splitNumber = splitNumber != null ? splitNumber : stepOpt.secs;
|
||
|
//this.option.splitNumber = splitNumber;
|
||
|
this._min = stepOpt.min;
|
||
|
this._max = stepOpt.max;
|
||
|
this._valueList = stepOpt.pnts;
|
||
|
this._reformLabelData();
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 格式化时间值
|
||
|
*/
|
||
|
_reformTimeValue : function() {
|
||
|
var splitNumber = this.option.splitNumber != null ? this.option.splitNumber : 5;
|
||
|
|
||
|
// 最优解
|
||
|
var curValue = ecDate.getAutoFormatter(this._min, this._max, splitNumber);
|
||
|
// 目标
|
||
|
var formatter = curValue.formatter;
|
||
|
var gapValue = curValue.gapValue;
|
||
|
|
||
|
this._valueList = [ecDate.getNewDate(this._min)];
|
||
|
var startGap;
|
||
|
switch (formatter) {
|
||
|
case 'week' :
|
||
|
startGap = ecDate.nextMonday(this._min);
|
||
|
break;
|
||
|
case 'month' :
|
||
|
startGap = ecDate.nextNthOnMonth(this._min, 1);
|
||
|
break;
|
||
|
case 'quarter' :
|
||
|
startGap = ecDate.nextNthOnQuarterYear(this._min, 1);
|
||
|
break;
|
||
|
case 'half-year' :
|
||
|
startGap = ecDate.nextNthOnHalfYear(this._min, 1);
|
||
|
break;
|
||
|
case 'year' :
|
||
|
startGap = ecDate.nextNthOnYear(this._min, 1);
|
||
|
break;
|
||
|
default :
|
||
|
// 大于2小时需要考虑时区不能直接取整
|
||
|
if (gapValue <= 3600000 * 2) {
|
||
|
startGap = (Math.floor(this._min / gapValue) + 1) * gapValue;
|
||
|
}
|
||
|
else {
|
||
|
startGap = ecDate.getNewDate(this._min - (-gapValue));
|
||
|
startGap.setHours(Math.round(startGap.getHours() / 6) * 6);
|
||
|
startGap.setMinutes(0);
|
||
|
startGap.setSeconds(0);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (startGap - this._min < gapValue / 2) {
|
||
|
startGap -= -gapValue;
|
||
|
}
|
||
|
|
||
|
// console.log(startGap,gapValue,this._min, this._max,formatter)
|
||
|
curValue = ecDate.getNewDate(startGap);
|
||
|
splitNumber *= 1.5;
|
||
|
while (splitNumber-- >= 0) {
|
||
|
if (formatter == 'month'
|
||
|
|| formatter == 'quarter'
|
||
|
|| formatter == 'half-year'
|
||
|
|| formatter == 'year'
|
||
|
) {
|
||
|
curValue.setDate(1);
|
||
|
}
|
||
|
if (this._max - curValue < gapValue / 2) {
|
||
|
break;
|
||
|
}
|
||
|
this._valueList.push(curValue);
|
||
|
curValue = ecDate.getNewDate(curValue - (-gapValue));
|
||
|
}
|
||
|
this._valueList.push(ecDate.getNewDate(this._max));
|
||
|
|
||
|
this._reformLabelData((function (formatterStr) {
|
||
|
return function (value) {
|
||
|
return ecDate.format(formatterStr, value);
|
||
|
};
|
||
|
})(formatter));
|
||
|
},
|
||
|
|
||
|
_customerValue: function () {
|
||
|
var accMath = require('../util/accMath');
|
||
|
var splitNumber = this.option.splitNumber != null ? this.option.splitNumber : 5;
|
||
|
var splitGap = (this._max - this._min) / splitNumber;
|
||
|
|
||
|
this._valueList = [];
|
||
|
for (var i = 0; i <= splitNumber; i++) {
|
||
|
this._valueList.push(accMath.accAdd(this._min, accMath.accMul(splitGap, i)));
|
||
|
}
|
||
|
this._reformLabelData();
|
||
|
},
|
||
|
|
||
|
_reformLogValue: function() {
|
||
|
// log数轴本质就是缩放,相当于默认this.option.scale === true,所以不修正_min和_max到0。
|
||
|
var thisOption = this.option;
|
||
|
var result = require('../util/smartLogSteps')({
|
||
|
dataMin: this._min,
|
||
|
dataMax: this._max,
|
||
|
logPositive: thisOption.logPositive,
|
||
|
logLabelBase: thisOption.logLabelBase,
|
||
|
splitNumber: thisOption.splitNumber
|
||
|
});
|
||
|
|
||
|
this._min = result.dataMin;
|
||
|
this._max = result.dataMax;
|
||
|
this._valueList = result.tickList;
|
||
|
// {value2Coord: {Function}, coord2Value: {Function}}
|
||
|
this._dataMappingMethods = result.dataMappingMethods;
|
||
|
|
||
|
this._reformLabelData(result.labelFormatter);
|
||
|
},
|
||
|
|
||
|
_reformLabelData: function (innerFormatter) {
|
||
|
this._valueLabel = [];
|
||
|
var formatter = this.option.axisLabel.formatter;
|
||
|
if (formatter) {
|
||
|
for (var i = 0, l = this._valueList.length; i < l; i++) {
|
||
|
if (typeof formatter === 'function') {
|
||
|
this._valueLabel.push(
|
||
|
innerFormatter
|
||
|
? formatter.call(this.myChart, this._valueList[i], innerFormatter)
|
||
|
: formatter.call(this.myChart, this._valueList[i])
|
||
|
);
|
||
|
}
|
||
|
else if (typeof formatter === 'string') {
|
||
|
this._valueLabel.push(
|
||
|
innerFormatter
|
||
|
? ecDate.format(formatter, this._valueList[i])
|
||
|
: formatter.replace('{value}',this._valueList[i])
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
for (var i = 0, l = this._valueList.length; i < l; i++) {
|
||
|
this._valueLabel.push(
|
||
|
innerFormatter
|
||
|
? innerFormatter(this._valueList[i])
|
||
|
: this.numAddCommas(this._valueList[i]) // 每三位默认加,格式化
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
getExtremum: function () {
|
||
|
this._calculateValue();
|
||
|
var dataMappingMethods = this._dataMappingMethods;
|
||
|
return {
|
||
|
min: this._min,
|
||
|
max: this._max,
|
||
|
dataMappingMethods: dataMappingMethods
|
||
|
? zrUtil.merge({}, dataMappingMethods) : null
|
||
|
};
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* 刷新
|
||
|
*/
|
||
|
refresh: function (newOption, newSeries) {
|
||
|
if (newOption) {
|
||
|
this.option = this.reformOption(newOption);
|
||
|
// 通用字体设置
|
||
|
this.option.axisLabel.textStyle = zrUtil.merge(
|
||
|
this.option.axisLabel.textStyle || {},
|
||
|
this.ecTheme.textStyle
|
||
|
);
|
||
|
this.series = newSeries;
|
||
|
}
|
||
|
if (this.zr) { // 数值轴的另外一个功能只是用来计算极值
|
||
|
this.clear();
|
||
|
this._buildShape();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// 根据值换算位置
|
||
|
getCoord: function (value) {
|
||
|
if (this._dataMappingMethods) {
|
||
|
value = this._dataMappingMethods.value2Coord(value);
|
||
|
}
|
||
|
|
||
|
value = value < this._min ? this._min : value;
|
||
|
value = value > this._max ? this._max : value;
|
||
|
|
||
|
var result;
|
||
|
if (!this.isHorizontal()) {
|
||
|
// 纵向
|
||
|
result = this.grid.getYend()
|
||
|
- (value - this._min)
|
||
|
/ (this._max - this._min)
|
||
|
* this.grid.getHeight();
|
||
|
}
|
||
|
else {
|
||
|
// 横向
|
||
|
result = this.grid.getX()
|
||
|
+ (value - this._min)
|
||
|
/ (this._max - this._min)
|
||
|
* this.grid.getWidth();
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
// Math.floor可能引起一些偏差,但性能会更好
|
||
|
/* 准确更重要
|
||
|
return (value === this._min || value === this._max)
|
||
|
? result
|
||
|
: Math.floor(result);
|
||
|
*/
|
||
|
},
|
||
|
|
||
|
// 根据值换算绝对大小
|
||
|
getCoordSize: function (value) {
|
||
|
if (!this.isHorizontal()) {
|
||
|
// 纵向
|
||
|
return Math.abs(value / (this._max - this._min) * this.grid.getHeight());
|
||
|
}
|
||
|
else {
|
||
|
// 横向
|
||
|
return Math.abs(value / (this._max - this._min) * this.grid.getWidth());
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// 根据位置换算值
|
||
|
getValueFromCoord: function(coord) {
|
||
|
var result;
|
||
|
|
||
|
if (!this.isHorizontal()) {
|
||
|
// 纵向
|
||
|
coord = coord < this.grid.getY() ? this.grid.getY() : coord;
|
||
|
coord = coord > this.grid.getYend() ? this.grid.getYend() : coord;
|
||
|
result = this._max
|
||
|
- (coord - this.grid.getY())
|
||
|
/ this.grid.getHeight()
|
||
|
* (this._max - this._min);
|
||
|
}
|
||
|
else {
|
||
|
// 横向
|
||
|
coord = coord < this.grid.getX() ? this.grid.getX() : coord;
|
||
|
coord = coord > this.grid.getXend() ? this.grid.getXend() : coord;
|
||
|
result = this._min
|
||
|
+ (coord - this.grid.getX())
|
||
|
/ this.grid.getWidth()
|
||
|
* (this._max - this._min);
|
||
|
}
|
||
|
|
||
|
if (this._dataMappingMethods) {
|
||
|
result = this._dataMappingMethods.coord2Value(result);
|
||
|
}
|
||
|
|
||
|
return result.toFixed(2) - 0;
|
||
|
},
|
||
|
|
||
|
isMaindAxis : function (value) {
|
||
|
for (var i = 0, l = this._valueList.length; i < l; i++) {
|
||
|
if (this._valueList[i] === value) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
zrUtil.inherits(ValueAxis, Base);
|
||
|
|
||
|
require('../component').define('valueAxis', ValueAxis);
|
||
|
|
||
|
return ValueAxis;
|
||
|
});
|
||
|
|