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.
345 lines
14 KiB
345 lines
14 KiB
/**
|
|
* echarts组件类: 坐标轴
|
|
*
|
|
* @desc echarts基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据统计图表。
|
|
* @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
|
|
*
|
|
* 直角坐标系中坐标轴数组,数组中每一项代表一条横轴(纵轴)坐标轴。
|
|
* 标准(1.0)中规定最多同时存在2条横轴和2条纵轴
|
|
* 单条横轴时可指定安放于grid的底部(默认)或顶部,2条同时存在时则默认第一条安放于底部,第二天安放于顶部
|
|
* 单条纵轴时可指定安放于grid的左侧(默认)或右侧,2条同时存在时则默认第一条安放于左侧,第二天安放于右侧。
|
|
* 坐标轴有两种类型,类目型和数值型(区别详见axis):
|
|
* 横轴通常为类目型,但条形图时则横轴为数值型,散点图时则横纵均为数值型
|
|
* 纵轴通常为数值型,但条形图时则纵轴为类目型。
|
|
*
|
|
*/
|
|
define(function (require) {
|
|
var Base = require('./base');
|
|
|
|
var LineShape = require('zrender/shape/Line');
|
|
|
|
var ecConfig = require('../config');
|
|
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} option 图表选项
|
|
* @param {string=} option.xAxis.type 坐标轴类型,横轴默认为类目型'category'
|
|
* @param {string=} option.yAxis.type 坐标轴类型,纵轴默认为类目型'value'
|
|
* @param {Object} component 组件
|
|
* @param {string} axisType 横走or纵轴
|
|
*/
|
|
function Axis(ecTheme, messageCenter, zr, option, myChart, axisType) {
|
|
Base.call(this, ecTheme, messageCenter, zr, option, myChart);
|
|
|
|
this.axisType = axisType;
|
|
this._axisList = [];
|
|
|
|
this.refresh(option);
|
|
}
|
|
|
|
Axis.prototype = {
|
|
type: ecConfig.COMPONENT_TYPE_AXIS,
|
|
axisBase: {
|
|
// 轴线
|
|
_buildAxisLine: function () {
|
|
var lineWidth = this.option.axisLine.lineStyle.width;
|
|
var halfLineWidth = lineWidth / 2;
|
|
var axShape = {
|
|
_axisShape: 'axisLine',
|
|
zlevel: this.getZlevelBase(),
|
|
z: this.getZBase() + 3,
|
|
hoverable: false
|
|
};
|
|
var grid = this.grid;
|
|
switch (this.option.position) {
|
|
case 'left' :
|
|
axShape.style = {
|
|
xStart: grid.getX() - halfLineWidth,
|
|
yStart: grid.getYend(),
|
|
xEnd: grid.getX() - halfLineWidth,
|
|
yEnd: grid.getY(),
|
|
lineCap: 'round'
|
|
};
|
|
break;
|
|
case 'right' :
|
|
axShape.style = {
|
|
xStart: grid.getXend() + halfLineWidth,
|
|
yStart: grid.getYend(),
|
|
xEnd: grid.getXend() + halfLineWidth,
|
|
yEnd: grid.getY(),
|
|
lineCap: 'round'
|
|
};
|
|
break;
|
|
case 'bottom' :
|
|
axShape.style = {
|
|
xStart: grid.getX(),
|
|
yStart: grid.getYend() + halfLineWidth,
|
|
xEnd: grid.getXend(),
|
|
yEnd: grid.getYend() + halfLineWidth,
|
|
lineCap: 'round'
|
|
};
|
|
break;
|
|
case 'top' :
|
|
axShape.style = {
|
|
xStart: grid.getX(),
|
|
yStart: grid.getY() - halfLineWidth,
|
|
xEnd: grid.getXend(),
|
|
yEnd: grid.getY() - halfLineWidth,
|
|
lineCap: 'round'
|
|
};
|
|
break;
|
|
}
|
|
var style = axShape.style;
|
|
if (this.option.name !== '') { // 别帮我代码规范
|
|
style.text = this.option.name;
|
|
style.textPosition = this.option.nameLocation;
|
|
style.textFont = this.getFont(this.option.nameTextStyle);
|
|
if (this.option.nameTextStyle.align) {
|
|
style.textAlign = this.option.nameTextStyle.align;
|
|
}
|
|
if (this.option.nameTextStyle.baseline) {
|
|
style.textBaseline = this.option.nameTextStyle.baseline;
|
|
}
|
|
if (this.option.nameTextStyle.color) {
|
|
style.textColor = this.option.nameTextStyle.color;
|
|
}
|
|
}
|
|
style.strokeColor = this.option.axisLine.lineStyle.color;
|
|
|
|
style.lineWidth = lineWidth;
|
|
// 亚像素优化
|
|
if (this.isHorizontal()) {
|
|
// 横向布局,优化y
|
|
style.yStart
|
|
= style.yEnd
|
|
= this.subPixelOptimize(style.yEnd, lineWidth);
|
|
}
|
|
else {
|
|
// 纵向布局,优化x
|
|
style.xStart
|
|
= style.xEnd
|
|
= this.subPixelOptimize(style.xEnd, lineWidth);
|
|
}
|
|
|
|
style.lineType = this.option.axisLine.lineStyle.type;
|
|
|
|
axShape = new LineShape(axShape);
|
|
this.shapeList.push(axShape);
|
|
},
|
|
|
|
_axisLabelClickable: function(clickable, axShape) {
|
|
if (clickable) {
|
|
ecData.pack(
|
|
axShape, undefined, -1, undefined, -1, axShape.style.text
|
|
);
|
|
axShape.hoverable = true;
|
|
axShape.clickable = true;
|
|
axShape.highlightStyle = {
|
|
color: zrColor.lift(axShape.style.color, 1),
|
|
brushType: 'fill'
|
|
};
|
|
return axShape;
|
|
}
|
|
else {
|
|
return axShape;
|
|
}
|
|
},
|
|
|
|
refixAxisShape: function(zeroX, zeroY) {
|
|
if (!this.option.axisLine.onZero) {
|
|
return;
|
|
}
|
|
var tickLength;
|
|
if (this.isHorizontal() && zeroY != null) {
|
|
// 横向布局调整纵向y
|
|
for (var i = 0, l = this.shapeList.length; i < l; i++) {
|
|
if (this.shapeList[i]._axisShape === 'axisLine') {
|
|
this.shapeList[i].style.yStart
|
|
= this.shapeList[i].style.yEnd
|
|
= this.subPixelOptimize(
|
|
zeroY, this.shapeList[i].stylelineWidth
|
|
);
|
|
this.zr.modShape(this.shapeList[i].id);
|
|
}
|
|
else if (this.shapeList[i]._axisShape === 'axisTick') {
|
|
tickLength = this.shapeList[i].style.yEnd
|
|
- this.shapeList[i].style.yStart;
|
|
this.shapeList[i].style.yStart = zeroY - tickLength;
|
|
this.shapeList[i].style.yEnd = zeroY;
|
|
this.zr.modShape(this.shapeList[i].id);
|
|
}
|
|
}
|
|
}
|
|
if (!this.isHorizontal() && zeroX != null) {
|
|
// 纵向布局调整横向x
|
|
for (var i = 0, l = this.shapeList.length; i < l; i++) {
|
|
if (this.shapeList[i]._axisShape === 'axisLine') {
|
|
this.shapeList[i].style.xStart
|
|
= this.shapeList[i].style.xEnd
|
|
= this.subPixelOptimize(
|
|
zeroX, this.shapeList[i].stylelineWidth
|
|
);
|
|
this.zr.modShape(this.shapeList[i].id);
|
|
}
|
|
else if (this.shapeList[i]._axisShape === 'axisTick') {
|
|
tickLength = this.shapeList[i].style.xEnd
|
|
- this.shapeList[i].style.xStart;
|
|
this.shapeList[i].style.xStart = zeroX;
|
|
this.shapeList[i].style.xEnd = zeroX + tickLength;
|
|
this.zr.modShape(this.shapeList[i].id);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
getPosition: function () {
|
|
return this.option.position;
|
|
},
|
|
|
|
isHorizontal: function() {
|
|
return this.option.position === 'bottom' || this.option.position === 'top';
|
|
}
|
|
},
|
|
/**
|
|
* 参数修正&默认值赋值,重载基类方法
|
|
* @param {Object} opt 参数
|
|
*/
|
|
reformOption: function (opt) {
|
|
// 不写或传了个空数值默认为数值轴
|
|
if (!opt || (opt instanceof Array && opt.length === 0)) {
|
|
opt = [ { type: ecConfig.COMPONENT_TYPE_AXIS_VALUE } ];
|
|
}
|
|
else if (!(opt instanceof Array)){
|
|
opt = [opt];
|
|
}
|
|
|
|
// 最多两条,其他参数忽略
|
|
if (opt.length > 2) {
|
|
opt = [opt[0], opt[1]];
|
|
}
|
|
|
|
if (this.axisType === 'xAxis') {
|
|
// 横轴位置默认配置
|
|
if (!opt[0].position // 没配置或配置错
|
|
|| (opt[0].position != 'bottom' && opt[0].position != 'top')
|
|
) {
|
|
opt[0].position = 'bottom';
|
|
}
|
|
if (opt.length > 1) {
|
|
opt[1].position = opt[0].position === 'bottom' ? 'top' : 'bottom';
|
|
}
|
|
|
|
for (var i = 0, l = opt.length; i < l; i++) {
|
|
// 坐标轴类型,横轴默认为类目型'category'
|
|
opt[i].type = opt[i].type || 'category';
|
|
// 标识轴类型&索引
|
|
opt[i].xAxisIndex = i;
|
|
opt[i].yAxisIndex = -1;
|
|
}
|
|
}
|
|
else {
|
|
// 纵轴位置默认配置
|
|
if (!opt[0].position // 没配置或配置错
|
|
|| (opt[0].position != 'left' && opt[0].position != 'right')
|
|
) {
|
|
opt[0].position = 'left';
|
|
}
|
|
|
|
if (opt.length > 1) {
|
|
opt[1].position = opt[0].position === 'left' ? 'right' : 'left';
|
|
}
|
|
|
|
for (var i = 0, l = opt.length; i < l; i++) {
|
|
// 坐标轴类型,纵轴默认为数值型'value'
|
|
opt[i].type = opt[i].type || 'value';
|
|
// 标识轴类型&索引
|
|
opt[i].xAxisIndex = -1;
|
|
opt[i].yAxisIndex = i;
|
|
}
|
|
}
|
|
|
|
return opt;
|
|
},
|
|
|
|
/**
|
|
* 刷新
|
|
*/
|
|
refresh: function (newOption) {
|
|
var axisOption;
|
|
if (newOption) {
|
|
this.option = newOption;
|
|
if (this.axisType === 'xAxis') {
|
|
this.option.xAxis = this.reformOption(newOption.xAxis);
|
|
axisOption = this.option.xAxis;
|
|
}
|
|
else {
|
|
this.option.yAxis = this.reformOption(newOption.yAxis);
|
|
axisOption = this.option.yAxis;
|
|
}
|
|
this.series = newOption.series;
|
|
}
|
|
|
|
var CategoryAxis = require('./categoryAxis');
|
|
var ValueAxis = require('./valueAxis');
|
|
var len = Math.max((axisOption && axisOption.length || 0), this._axisList.length);
|
|
for (var i = 0; i < len; i++) {
|
|
if (this._axisList[i] // 已有实例
|
|
&& newOption // 非空刷新
|
|
&& (!axisOption[i] || this._axisList[i].type != axisOption[i].type) // 类型不匹配
|
|
) {
|
|
this._axisList[i].dispose && this._axisList[i].dispose();
|
|
this._axisList[i] = false;
|
|
}
|
|
|
|
if (this._axisList[i]) {
|
|
this._axisList[i].refresh && this._axisList[i].refresh(
|
|
axisOption ? axisOption[i] : false,
|
|
this.series
|
|
);
|
|
}
|
|
else if (axisOption && axisOption[i]) {
|
|
this._axisList[i] = axisOption[i].type === 'category'
|
|
? new CategoryAxis(
|
|
this.ecTheme, this.messageCenter, this.zr,
|
|
axisOption[i], this.myChart, this.axisBase
|
|
)
|
|
: new ValueAxis(
|
|
this.ecTheme, this.messageCenter, this.zr,
|
|
axisOption[i], this.myChart, this.axisBase,
|
|
this.series
|
|
);
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* 根据值换算位置
|
|
* @param {number} idx 坐标轴索引0~1
|
|
*/
|
|
getAxis: function (idx) {
|
|
return this._axisList[idx];
|
|
},
|
|
|
|
getAxisCount: function () {
|
|
return this._axisList.length;
|
|
},
|
|
|
|
clear: function () {
|
|
for (var i = 0, l = this._axisList.length; i < l; i++) {
|
|
this._axisList[i].dispose && this._axisList[i].dispose();
|
|
}
|
|
this._axisList = [];
|
|
}
|
|
};
|
|
|
|
zrUtil.inherits(Axis, Base);
|
|
|
|
require('../component').define('axis', Axis);
|
|
|
|
return Axis;
|
|
});
|
|
|