之前用过一阵子echarts做APP上的趋势图,修改过源码实现一些自定义效果。以及设置一些echarts-m.js的隐藏setting,在此Mark一下,防止忘记。
1. 自定义tooltip绘制轨迹。
echarts提供的tooltip,在绘制直线时,只提供了实线,虚线,阴影线。如果要在直线的基础上,增加一些功能,比如线要超出图的边界(如果用formatter事件注入,会有延迟效果),就需要修改一下源码,指导内部的绘制路径,因为echarts本身就是用canvas画tootip的。废话不多说。
A. 新增Config属性。
在'echarts/component/tooltip'模块下,ecConfig.tooltip的定义中,扩展下axisPointer,新增selfDefine属性,默认为String,不启用。传入function可以覆盖使用。
axisPointer: {
type: 'line',
lineStyle: {
color: '#48b',
width: 2,
type: 'solid',
selfDefine : 'self defined function to help draw tip panel' //modify, new add
},
crossStyle: {
color: '#1e90ff',
width: 1,
type: 'dashed',
selfDefine : 'self defined function to help draw tip panel' //modify, new add
},
shadowStyle: {
color: 'rgba(150,150,150,0.3)',
width: 'auto',
type: 'default',
selfDefine : 'self defined function to help draw tip panel' //modify, new add
}
},
B. 在Tooltip.prototype = {}的定义中,修改_styleAxisPointer方法,注意//new add 注解部分为selfDefine方法的注入。
_styleAxisPointer: function (seriesArray, xStart, yStart, xEnd, yEnd, gap, x, y) {
if (seriesArray.length > 0) {
var queryTarget;
var curType;
var axisPointer = this.option.tooltip.axisPointer;
var pointType = axisPointer.type;
var appendStyle = this.option.tooltip.appendStyle;
var style = {
line: {},
cross: {},
shadow: {}
};
for (var pType in style) {
style[pType].color = axisPointer[pType + 'Style'].color;
style[pType].width = axisPointer[pType + 'Style'].width;
style[pType].type = axisPointer[pType + 'Style'].type;
style[pType].selfDefine = axisPointer[pType + 'Style'].selfDefine; // new add
}
for (var i = 0, l = seriesArray.length; i < l; i++) {
queryTarget = seriesArray[i];
curType = this.query(queryTarget, 'tooltip.axisPointer.type');
pointType = curType || pointType;
if (curType) {
style[curType].color = this.query(queryTarget, 'tooltip.axisPointer.' + curType + 'Style.color') || style[curType].color;
style[curType].width = this.query(queryTarget, 'tooltip.axisPointer.' + curType + 'Style.width') || style[curType].width;
style[curType].type = this.query(queryTarget, 'tooltip.axisPointer.' + curType + 'Style.type') || style[curType].type;
style[curType].selfDefine = style[curType].selfDefine; //new add
}
}
if (pointType === 'line') {
var lineWidth = style.line.width;
var isVertical = xStart == xEnd;
this._axisLineShape.style = {
xStart: isVertical ? this.subPixelOptimize(xStart, lineWidth) : xStart,
yStart: isVertical ? yStart : this.subPixelOptimize(yStart, lineWidth),
xEnd: isVertical ? this.subPixelOptimize(xEnd, lineWidth) : xEnd,
yEnd: isVertical ? yEnd : this.subPixelOptimize(yEnd, lineWidth),
strokeColor: style.line.color,
lineWidth: lineWidth,
lineType: style.line.type,
selfDefine : style.line.selfDefine //new add
};
this._axisLineShape.invisible = false;
this.zr.modShape(this._axisLineShape.id);
} else if (pointType === 'cross') {
var crossWidth = style.cross.width;
this._axisCrossShape.style = {
brushType: 'stroke',
rect: this.component.grid.getArea(),
x: this.subPixelOptimize(x, crossWidth),
y: this.subPixelOptimize(y, crossWidth),
text: ('( ' + this.component.xAxis.getAxis(0).getValueFromCoord(x) + ' , ' + this.component.yAxis.getAxis(0).getValueFromCoord(y) + ' )').replace(' , ', ' ').replace(' , ', ' '),
textPosition: 'specific',
strokeColor: style.cross.color,
lineWidth: crossWidth,
lineType: style.cross.type
};
if (this.component.grid.getXend() - x > 100) {
this._axisCrossShape.style.textAlign = 'left';
this._axisCrossShape.style.textX = x + 10;
} else {
this._axisCrossShape.style.textAlign = 'right';
this._axisCrossShape.style.textX = x - 10;
}
if (y - this.component.grid.getY() > 50) {
this._axisCrossShape.style.textBaseline = 'bottom';
this._axisCrossShape.style.textY = y - 10;
} else {
this._axisCrossShape.style.textBaseline = 'top';
this._axisCrossShape.style.textY = y + 10;
}
this._axisCrossShape.invisible = false;
this.zr.modShape(this._axisCrossShape.id);
} else if (pointType === 'shadow') {
if (style.shadow.width == null || style.shadow.width === 'auto' || isNaN(style.shadow.width)) {
style.shadow.width = gap;
}
if (xStart === xEnd) {
if (Math.abs(this.component.grid.getX() - xStart) < 2) {
style.shadow.width /= 2;
xStart = xEnd = xEnd + style.shadow.width / 2;
} else if (Math.abs(this.component.grid.getXend() - xStart) < 2) {
style.shadow.width /= 2;
xStart = xEnd = xEnd - style.shadow.width / 2;
}
} else if (yStart === yEnd) {
if (Math.abs(this.component.grid.getY() - yStart) < 2) {
style.shadow.width /= 2;
yStart = yEnd = yEnd + style.shadow.width / 2;
} else if (Math.abs(this.component.grid.getYend() - yStart) < 2) {
style.shadow.width /= 2;
yStart = yEnd = yEnd - style.shadow.width / 2;
}
}
this._axisShadowShape.style = {
xStart: xStart,
yStart: yStart,
xEnd: xEnd,
yEnd: yEnd,
strokeColor: style.shadow.color,
lineWidth: style.shadow.width
};
this._axisShadowShape.invisible = false;
this.zr.modShape(this._axisShadowShape.id);
}
this.zr.refreshNextFrame();
if(appendStyle && (typeof appendStyle === 'function')){ //new add
appendStyle.call(this, x, y);
}
}
},
C. 修改模块'zrender/shape/Line', Line.prototype = {} 的定义处,指导buildPath绘制。如果有传入selfDefine函数,使用selfDefine的画图路径,通过这种方式,可以绘制各种样式,不一定要按照echarts提供的几种tooltip.
Line.prototype = {
type: 'line',
buildPath: function (ctx, style) {
if(style.selfDefine && (typeof style.selfDefine === 'function')){
// console.log(style.xStart+" "+style.yStart+" "+style.xEnd+" "+style.yEnd);
var selfDefine = style.selfDefine;
selfDefine.call(this,ctx,style.xStart,style.yStart,style.xEnd,style.yEnd);
return;
}else if (!style.lineType || style.lineType == 'solid') {
// console.log('solid line');
ctx.moveTo(style.xStart, style.yStart);
ctx.lineTo(style.xEnd, style.yEnd);
} else if (style.lineType == 'dashed' || style.lineType == 'dotted') {
// console.log('dash line');
var dashLength = (style.lineWidth || 1) * (style.lineType == 'dashed' ? 5 : 1);
dashedLineTo(ctx, style.xStart, style.yStart, style.xEnd, style.yEnd, dashLength);
}
},
getRect: function (style) {
if (style.__rect) {
return style.__rect;
}
var lineWidth = style.lineWidth || 1;
style.__rect = {
x: Math.min(style.xStart, style.xEnd) - lineWidth,
y: Math.min(style.yStart, style.yEnd) - lineWidth,
width: Math.abs(style.xStart - style.xEnd) + lineWidth,
height: Math.abs(style.yStart - style.yEnd) + lineWidth
};
return style.__rect;
}
};
D. 使用。
修改完成后,使用配置如下。通过设置yStart-26后,可以使tooltip线超出echarts的网格区域。
tooltip: {
showDelay:0,
transitionDuration:0,
backgroundColor: "#a6afb6",
borderColor: "yellow",
borderWidth: 2,
padding: 0,
showContent: false,
trigger: 'axis', //item,axis
position: function() {
return [0, 0];
},
formatter: function(params) {
},
axisPointer: {
type: 'line',
lineStyle: {
width: 2,
color :"#a6afb6",
selfDefine: function(ctx,xStart,yStart,xEnd,yEnd){
ctx.moveTo(xStart, yStart-26);
ctx.lineTo(xEnd, yEnd);
}
}
}
},
2. echarts-m.
echarts提供了一个m版本,删除了很多PC事件,适用于APP, 但是API和PC版有一些不一致,尤其是Y轴坐标值默认在右侧,太蛋疼。通过查看源代码,找到了这些默认设置。记录如下:
1. Y轴坐标值水平位置
yAxis > axisLabel > margin ,设置为35,可以调整。
yAxis: [{
type: 'value',
lineStyle: {
color: '#a6afb6',
width: 1,
type: 'solid'
},
axisLine: {
lineStyle: {
color: '#a6afb6',
width: 1,
type: 'solid'
}
},
axisLabel: {
textStyle: {
color: '#a6afb6'
},
margin: 35, //modify for ehcarts-m
align: 'right',
formatter: function(value){
if(value >= 10000000){
value = value/1000000;
value = value+"M";
}else if(value >= 10000){
value = value/1000;
value = value+"K";
}else{
value = value+"";
}
for(var i = value.length ; i < 5;i++){
value = " "+value;
}
return value;
}
}
}],
B. max3显示重复趋势线段。
设置animation:false
最后,有问题,欢迎交流。