之前用過一陣子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,axisposition: 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-malign: '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
最後,有問題,歡迎交流。