/** | |
* 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]; | |
}, | |
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; | |
}); |