/** | |
* echarts组件:提示框 | |
* | |
* @desc echarts基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据统计图表。 | |
* @author Kener (@Kener-林峰, kener.linfeng@gmail.com) | |
* | |
*/ | |
define(function (require) { | |
var Base = require('./base'); | |
// 图形依赖 | |
var CrossShape = require('../util/shape/Cross'); | |
var LineShape = require('zrender/shape/Line'); | |
var RectangleShape = require('zrender/shape/Rectangle'); | |
var rectangleInstance = new RectangleShape({}); | |
var ecConfig = require('../config'); | |
// 提示框 | |
ecConfig.tooltip = { | |
zlevel: 1, // 一级层叠,频繁变化的tooltip指示器在pc上独立一层 | |
z: 8, // 二级层叠 | |
show: true, | |
showContent: true, // tooltip主体内容 | |
trigger: 'item', // 触发类型,默认数据触发,见下图,可选为:'item' ¦ 'axis' | |
// position: null // 位置 {Array} | {Function} | |
// formatter: null // 内容格式器:{string}(Template) ¦ {Function} | |
islandFormatter: '{a} <br/>{b} : {c}', // 数据孤岛内容格式器 | |
showDelay: 20, // 显示延迟,添加显示延迟可以避免频繁切换,单位ms | |
hideDelay: 100, // 隐藏延迟,单位ms | |
transitionDuration: 0.4, // 动画变换时间,单位s | |
enterable: false, | |
backgroundColor: 'rgba(0,0,0,0.7)', // 提示背景颜色,默认为透明度为0.7的黑色 | |
borderColor: '#333', // 提示边框颜色 | |
borderRadius: 4, // 提示边框圆角,单位px,默认为4 | |
borderWidth: 0, // 提示边框线宽,单位px,默认为0(无边框) | |
padding: 5, // 提示内边距,单位px,默认各方向内边距为5, | |
// 接受数组分别设定上右下左边距,同css | |
axisPointer: { // 坐标轴指示器,坐标轴触发有效 | |
type: 'line', // 默认为直线,可选为:'line' | 'shadow' | 'cross' | |
lineStyle: { // 直线指示器样式设置 | |
color: '#48b', | |
width: 2, | |
type: 'solid' | |
}, | |
crossStyle: { | |
color: '#1e90ff', | |
width: 1, | |
type: 'dashed' | |
}, | |
shadowStyle: { // 阴影指示器样式设置 | |
color: 'rgba(150,150,150,0.3)', // 阴影颜色 | |
width: 'auto', // 阴影大小 | |
type: 'default' | |
} | |
}, | |
textStyle: { | |
color: '#fff' | |
} | |
}; | |
var ecData = require('../util/ecData'); | |
var zrConfig = require('zrender/config'); | |
var zrEvent = require('zrender/tool/event'); | |
var zrArea = require('zrender/tool/area'); | |
var zrColor = require('zrender/tool/color'); | |
var zrUtil = require('zrender/tool/util'); | |
var zrShapeBase = require('zrender/shape/Base'); | |
/** | |
* 构造函数 | |
* @param {Object} messageCenter echart消息中心 | |
* @param {ZRender} zr zrender实例 | |
* @param {Object} option 提示框参数 | |
* @param {HtmlElement} dom 目标对象 | |
* @param {ECharts} myChart 当前图表实例 | |
*/ | |
function Tooltip(ecTheme, messageCenter, zr, option, myChart) { | |
Base.call(this, ecTheme, messageCenter, zr, option, myChart); | |
this.dom = myChart.dom; | |
var self = this; | |
self._onmousemove = function (param) { | |
return self.__onmousemove(param); | |
}; | |
self._onglobalout = function (param) { | |
return self.__onglobalout(param); | |
}; | |
this.zr.on(zrConfig.EVENT.MOUSEMOVE, self._onmousemove); | |
this.zr.on(zrConfig.EVENT.GLOBALOUT, self._onglobalout); | |
self._hide = function (param) { | |
return self.__hide(param); | |
}; | |
self._tryShow = function(param) { | |
return self.__tryShow(param); | |
}; | |
self._refixed = function(param) { | |
return self.__refixed(param); | |
}; | |
self._setContent = function(ticket, res) { | |
return self.__setContent(ticket, res); | |
}; | |
this._tDom = this._tDom || document.createElement('div'); | |
// 避免拖拽时页面选中的尴尬 | |
this._tDom.onselectstart = function() { | |
return false; | |
}; | |
this._tDom.onmouseover = function() { | |
self._mousein = true; | |
}; | |
this._tDom.onmouseout = function() { | |
self._mousein = false; | |
}; | |
this._tDom.className = 'echarts-tooltip'; | |
this._tDom.style.position = 'absolute'; // 不是多余的,别删! | |
this.hasAppend = false; | |
this._axisLineShape && this.zr.delShape(this._axisLineShape.id); | |
this._axisLineShape = new LineShape({ | |
zlevel: this.getZlevelBase(), | |
z: this.getZBase(), | |
invisible: true, | |
hoverable: false | |
}); | |
this.shapeList.push(this._axisLineShape); | |
this.zr.addShape(this._axisLineShape); | |
this._axisShadowShape && this.zr.delShape(this._axisShadowShape.id); | |
this._axisShadowShape = new LineShape({ | |
zlevel: this.getZlevelBase(), | |
z: 1, // grid上,chart下 | |
invisible: true, | |
hoverable: false | |
}); | |
this.shapeList.push(this._axisShadowShape); | |
this.zr.addShape(this._axisShadowShape); | |
this._axisCrossShape && this.zr.delShape(this._axisCrossShape.id); | |
this._axisCrossShape = new CrossShape({ | |
zlevel: this.getZlevelBase(), | |
z: this.getZBase(), | |
invisible: true, | |
hoverable: false | |
}); | |
this.shapeList.push(this._axisCrossShape); | |
this.zr.addShape(this._axisCrossShape); | |
this.showing = false; | |
this.refresh(option); | |
} | |
Tooltip.prototype = { | |
type: ecConfig.COMPONENT_TYPE_TOOLTIP, | |
// 通用样式 | |
_gCssText: 'position:absolute;display:block;border-style:solid;white-space:nowrap;', | |
/** | |
* 根据配置设置dom样式 | |
*/ | |
_style: function (opt) { | |
if (!opt) { | |
return ''; | |
} | |
var cssText = []; | |
if (opt.transitionDuration) { | |
var transitionText = 'left ' + opt.transitionDuration + 's,' | |
+ 'top ' + opt.transitionDuration + 's'; | |
cssText.push( | |
'transition:' + transitionText | |
); | |
cssText.push( | |
'-moz-transition:' + transitionText | |
); | |
cssText.push( | |
'-webkit-transition:' + transitionText | |
); | |
cssText.push( | |
'-o-transition:' + transitionText | |
); | |
} | |
if (opt.backgroundColor) { | |
// for sb ie~ | |
cssText.push( | |
'background-Color:' + zrColor.toHex( | |
opt.backgroundColor | |
) | |
); | |
cssText.push('filter:alpha(opacity=70)'); | |
cssText.push('background-Color:' + opt.backgroundColor); | |
} | |
if (opt.borderWidth != null) { | |
cssText.push('border-width:' + opt.borderWidth + 'px'); | |
} | |
if (opt.borderColor != null) { | |
cssText.push('border-color:' + opt.borderColor); | |
} | |
if (opt.borderRadius != null) { | |
cssText.push( | |
'border-radius:' + opt.borderRadius + 'px' | |
); | |
cssText.push( | |
'-moz-border-radius:' + opt.borderRadius + 'px' | |
); | |
cssText.push( | |
'-webkit-border-radius:' + opt.borderRadius + 'px' | |
); | |
cssText.push( | |
'-o-border-radius:' + opt.borderRadius + 'px' | |
); | |
} | |
var textStyle = opt.textStyle; | |
if (textStyle) { | |
textStyle.color && cssText.push('color:' + textStyle.color); | |
textStyle.decoration && cssText.push( | |
'text-decoration:' + textStyle.decoration | |
); | |
textStyle.align && cssText.push( | |
'text-align:' + textStyle.align | |
); | |
textStyle.fontFamily && cssText.push( | |
'font-family:' + textStyle.fontFamily | |
); | |
textStyle.fontSize && cssText.push( | |
'font-size:' + textStyle.fontSize + 'px' | |
); | |
textStyle.fontSize && cssText.push( | |
'line-height:' + Math.round(textStyle.fontSize*3/2) + 'px' | |
); | |
textStyle.fontStyle && cssText.push( | |
'font-style:' + textStyle.fontStyle | |
); | |
textStyle.fontWeight && cssText.push( | |
'font-weight:' + textStyle.fontWeight | |
); | |
} | |
var padding = opt.padding; | |
if (padding != null) { | |
padding = this.reformCssArray(padding); | |
cssText.push( | |
'padding:' + padding[0] + 'px ' | |
+ padding[1] + 'px ' | |
+ padding[2] + 'px ' | |
+ padding[3] + 'px' | |
); | |
} | |
cssText = cssText.join(';') + ';'; | |
return cssText; | |
}, | |
__hide: function () { | |
this._lastDataIndex = -1; | |
this._lastSeriesIndex = -1; | |
this._lastItemTriggerId = -1; | |
if (this._tDom) { | |
this._tDom.style.display = 'none'; | |
} | |
var needRefresh = false; | |
if (!this._axisLineShape.invisible) { | |
this._axisLineShape.invisible = true; | |
this.zr.modShape(this._axisLineShape.id); | |
needRefresh = true; | |
} | |
if (!this._axisShadowShape.invisible) { | |
this._axisShadowShape.invisible = true; | |
this.zr.modShape(this._axisShadowShape.id); | |
needRefresh = true; | |
} | |
if (!this._axisCrossShape.invisible) { | |
this._axisCrossShape.invisible = true; | |
this.zr.modShape(this._axisCrossShape.id); | |
needRefresh = true; | |
} | |
if (this._lastTipShape && this._lastTipShape.tipShape.length > 0) { | |
this.zr.delShape(this._lastTipShape.tipShape); | |
this._lastTipShape = false; | |
this.shapeList.length = 2; | |
} | |
needRefresh && this.zr.refreshNextFrame(); | |
this.showing = false; | |
}, | |
_show: function (position, x, y, specialCssText) { | |
var domHeight = this._tDom.offsetHeight; | |
var domWidth = this._tDom.offsetWidth; | |
if (position) { | |
if (typeof position === 'function') { | |
position = position([x, y]); | |
} | |
if (position instanceof Array) { | |
x = position[0]; | |
y = position[1]; | |
} | |
} | |
if (x + domWidth > this._zrWidth) { | |
// 太靠右 | |
//x = this._zrWidth - domWidth; | |
x -= (domWidth + 40); | |
} | |
if (y + domHeight > this._zrHeight) { | |
// 太靠下 | |
//y = this._zrHeight - domHeight; | |
y -= (domHeight - 20); | |
} | |
if (y < 20) { | |
y = 0; | |
} | |
this._tDom.style.cssText = this._gCssText | |
+ this._defaultCssText | |
+ (specialCssText ? specialCssText : '') | |
+ 'left:' + x + 'px;top:' + y + 'px;'; | |
if (domHeight < 10 || domWidth < 10) { | |
// this._zrWidth - x < 100 || this._zrHeight - y < 100 | |
setTimeout(this._refixed, 20); | |
} | |
this.showing = true; | |
}, | |
__refixed: function () { | |
if (this._tDom) { | |
var cssText = ''; | |
var domHeight = this._tDom.offsetHeight; | |
var domWidth = this._tDom.offsetWidth; | |
if (this._tDom.offsetLeft + domWidth > this._zrWidth) { | |
cssText += 'left:' + (this._zrWidth - domWidth - 20) + 'px;'; | |
} | |
if (this._tDom.offsetTop + domHeight > this._zrHeight) { | |
cssText += 'top:' + (this._zrHeight - domHeight - 10) + 'px;'; | |
} | |
if (cssText !== '') { | |
this._tDom.style.cssText += cssText; | |
} | |
} | |
}, | |
__tryShow: function () { | |
var needShow; | |
var trigger; | |
if (!this._curTarget) { | |
// 坐标轴事件 | |
this._findPolarTrigger() || this._findAxisTrigger(); | |
} | |
else { | |
// 数据项事件 | |
if (this._curTarget._type === 'island' && this.option.tooltip.show) { | |
this._showItemTrigger(); | |
return; | |
} | |
var serie = ecData.get(this._curTarget, 'series'); | |
var data = ecData.get(this._curTarget, 'data'); | |
needShow = this.deepQuery( | |
[data, serie, this.option], | |
'tooltip.show' | |
); | |
if (serie == null || data == null || !needShow) { | |
// 不响应tooltip的数据对象延时隐藏 | |
clearTimeout(this._hidingTicket); | |
clearTimeout(this._showingTicket); | |
this._hidingTicket = setTimeout(this._hide, this._hideDelay); | |
} | |
else { | |
trigger = this.deepQuery( | |
[data, serie, this.option], | |
'tooltip.trigger' | |
); | |
trigger === 'axis' | |
? this._showAxisTrigger( | |
serie.xAxisIndex, serie.yAxisIndex, | |
ecData.get(this._curTarget, 'dataIndex') | |
) | |
: this._showItemTrigger(); | |
} | |
} | |
}, | |
/** | |
* 直角系 | |
*/ | |
_findAxisTrigger: function () { | |
if (!this.component.xAxis || !this.component.yAxis) { | |
this._hidingTicket = setTimeout(this._hide, this._hideDelay); | |
return; | |
} | |
var series = this.option.series; | |
var xAxisIndex; | |
var yAxisIndex; | |
for (var i = 0, l = series.length; i < l; i++) { | |
// 找到第一个axis触发tooltip的系列 | |
if (this.deepQuery([series[i], this.option], 'tooltip.trigger') === 'axis') { | |
xAxisIndex = series[i].xAxisIndex || 0; | |
yAxisIndex = series[i].yAxisIndex || 0; | |
if (this.component.xAxis.getAxis(xAxisIndex) | |
&& this.component.xAxis.getAxis(xAxisIndex).type | |
=== ecConfig.COMPONENT_TYPE_AXIS_CATEGORY | |
) { | |
// 横轴为类目轴 | |
this._showAxisTrigger(xAxisIndex, yAxisIndex, | |
this._getNearestDataIndex( | |
'x', this.component.xAxis.getAxis(xAxisIndex) | |
) | |
); | |
return; | |
} | |
else if (this.component.yAxis.getAxis(yAxisIndex) | |
&& this.component.yAxis.getAxis(yAxisIndex).type | |
=== ecConfig.COMPONENT_TYPE_AXIS_CATEGORY | |
) { | |
// 纵轴为类目轴 | |
this._showAxisTrigger(xAxisIndex, yAxisIndex, | |
this._getNearestDataIndex( | |
'y', this.component.yAxis.getAxis(yAxisIndex) | |
) | |
); | |
return; | |
} | |
else { | |
// 双数值轴 | |
this._showAxisTrigger(xAxisIndex, yAxisIndex, -1); | |
return; | |
} | |
} | |
} | |
if (this.option.tooltip.axisPointer.type === 'cross') { | |
this._showAxisTrigger(-1, -1, -1); | |
} | |
}, | |
/** | |
* 极坐标 | |
*/ | |
_findPolarTrigger: function () { | |
if (!this.component.polar) { | |
return false; | |
} | |
var x = zrEvent.getX(this._event); | |
var y = zrEvent.getY(this._event); | |
var polarIndex = this.component.polar.getNearestIndex([x, y]); | |
var valueIndex; | |
if (polarIndex) { | |
valueIndex = polarIndex.valueIndex; | |
polarIndex = polarIndex.polarIndex; | |
} | |
else { | |
polarIndex = -1; | |
} | |
if (polarIndex != -1) { | |
return this._showPolarTrigger(polarIndex, valueIndex); | |
} | |
return false; | |
}, | |
/** | |
* 根据坐标轴事件带的属性获取最近的axisDataIndex | |
*/ | |
_getNearestDataIndex: function (direction, categoryAxis) { | |
var dataIndex = -1; | |
var x = zrEvent.getX(this._event); | |
var y = zrEvent.getY(this._event); | |
if (direction === 'x') { | |
// 横轴为类目轴 | |
var left; | |
var right; | |
var xEnd = this.component.grid.getXend(); | |
var curCoord = categoryAxis.getCoordByIndex(dataIndex); | |
while (curCoord < xEnd) { | |
right = curCoord; | |
if (curCoord <= x) { | |
left = curCoord; | |
} | |
else { | |
break; | |
} | |
curCoord = categoryAxis.getCoordByIndex(++dataIndex); | |
} | |
if (dataIndex <= 0) { | |
dataIndex = 0; | |
} | |
else if (x - left <= right - x) { | |
dataIndex -= 1; | |
} | |
else { | |
// 离右边近,看是否为最后一个 | |
if (categoryAxis.getNameByIndex(dataIndex) == null) { | |
dataIndex -= 1; | |
} | |
} | |
return dataIndex; | |
} | |
else { | |
// 纵轴为类目轴 | |
var top; | |
var bottom; | |
var yStart = this.component.grid.getY(); | |
var curCoord = categoryAxis.getCoordByIndex(dataIndex); | |
while (curCoord > yStart) { | |
top = curCoord; | |
if (curCoord >= y) { | |
bottom = curCoord; | |
} | |
else { | |
break; | |
} | |
curCoord = categoryAxis.getCoordByIndex(++dataIndex); | |
} | |
if (dataIndex <= 0) { | |
dataIndex = 0; | |
} | |
else if (y - top >= bottom - y) { | |
dataIndex -= 1; | |
} | |
else { | |
// 离上方边近,看是否为最后一个 | |
if (categoryAxis.getNameByIndex(dataIndex) == null) { | |
dataIndex -= 1; | |
} | |
} | |
return dataIndex; | |
} | |
return -1; | |
}, | |
/** | |
* 直角系 | |
*/ | |
_showAxisTrigger: function (xAxisIndex, yAxisIndex, dataIndex) { | |
!this._event.connectTrigger && this.messageCenter.dispatch( | |
ecConfig.EVENT.TOOLTIP_IN_GRID, | |
this._event, | |
null, | |
this.myChart | |
); | |
if (this.component.xAxis == null | |
|| this.component.yAxis == null | |
|| xAxisIndex == null | |
|| yAxisIndex == null | |
// || dataIndex < 0 | |
) { | |
// 不响应tooltip的数据对象延时隐藏 | |
clearTimeout(this._hidingTicket); | |
clearTimeout(this._showingTicket); | |
this._hidingTicket = setTimeout(this._hide, this._hideDelay); | |
return; | |
} | |
var series = this.option.series; | |
var seriesArray = []; | |
var seriesIndex = []; | |
var categoryAxis; | |
var formatter; | |
var position; | |
var showContent; | |
var specialCssText = ''; | |
if (this.option.tooltip.trigger === 'axis') { | |
if (!this.option.tooltip.show) { | |
return; | |
} | |
formatter = this.option.tooltip.formatter; | |
position = this.option.tooltip.position; | |
} | |
var axisLayout = xAxisIndex != -1 | |
&& this.component.xAxis.getAxis(xAxisIndex).type | |
=== ecConfig.COMPONENT_TYPE_AXIS_CATEGORY | |
? 'xAxis' // 横轴为类目轴,找到所有用这条横轴并且axis触发的系列数据 | |
: yAxisIndex != -1 | |
&& this.component.yAxis.getAxis(yAxisIndex).type | |
=== ecConfig.COMPONENT_TYPE_AXIS_CATEGORY | |
? 'yAxis' // 纵轴为类目轴,找到所有用这条纵轴并且axis触发的系列数据 | |
: false; | |
var x; | |
var y; | |
if (axisLayout) { | |
var axisIndex = axisLayout == 'xAxis' ? xAxisIndex : yAxisIndex; | |
categoryAxis = this.component[axisLayout].getAxis(axisIndex); | |
for (var i = 0, l = series.length; i < l; i++) { | |
if (!this._isSelected(series[i].name)) { | |
continue; | |
} | |
if (series[i][axisLayout + 'Index'] === axisIndex | |
&& this.deepQuery([series[i], this.option], 'tooltip.trigger') === 'axis' | |
) { | |
showContent = this.query(series[i], 'tooltip.showContent') | |
|| showContent; | |
formatter = this.query(series[i], 'tooltip.formatter') | |
|| formatter; | |
position = this.query(series[i], 'tooltip.position') | |
|| position; | |
specialCssText += this._style(this.query(series[i], 'tooltip')); | |
if (series[i].stack != null && axisLayout == 'xAxis') { | |
seriesArray.unshift(series[i]); | |
seriesIndex.unshift(i); | |
} | |
else { | |
seriesArray.push(series[i]); | |
seriesIndex.push(i); | |
} | |
} | |
} | |
// 寻找高亮元素 | |
this.messageCenter.dispatch( | |
ecConfig.EVENT.TOOLTIP_HOVER, | |
this._event, | |
{ | |
seriesIndex: seriesIndex, | |
dataIndex: dataIndex | |
}, | |
this.myChart | |
); | |
var rect; | |
if (axisLayout == 'xAxis') { | |
x = this.subPixelOptimize( | |
categoryAxis.getCoordByIndex(dataIndex), | |
this._axisLineWidth | |
); | |
y = zrEvent.getY(this._event); | |
rect = [ | |
x, this.component.grid.getY(), | |
x, this.component.grid.getYend() | |
]; | |
} | |
else { | |
x = zrEvent.getX(this._event); | |
y = this.subPixelOptimize( | |
categoryAxis.getCoordByIndex(dataIndex), | |
this._axisLineWidth | |
); | |
rect = [ | |
this.component.grid.getX(), y, | |
this.component.grid.getXend(), y | |
]; | |
} | |
this._styleAxisPointer( | |
seriesArray, | |
rect[0], rect[1], rect[2], rect[3], | |
categoryAxis.getGap(), x, y | |
); | |
} | |
else { | |
// 双数值轴 | |
x = zrEvent.getX(this._event); | |
y = zrEvent.getY(this._event); | |
this._styleAxisPointer( | |
series, | |
this.component.grid.getX(), y, | |
this.component.grid.getXend(), y, | |
0, x, y | |
); | |
if (dataIndex >= 0) { | |
this._showItemTrigger(true); | |
} | |
else { | |
clearTimeout(this._hidingTicket); | |
clearTimeout(this._showingTicket); | |
this._tDom.style.display = 'none'; | |
} | |
} | |
if (seriesArray.length > 0) { | |
// 复位item trigger和axis trigger间短距离来回变换时的不响应 | |
this._lastItemTriggerId = -1; | |
// 相同dataIndex seriesIndex时不再触发内容更新 | |
if (this._lastDataIndex != dataIndex || this._lastSeriesIndex != seriesIndex[0]) { | |
this._lastDataIndex = dataIndex; | |
this._lastSeriesIndex = seriesIndex[0]; | |
var data; | |
var value; | |
if (typeof formatter === 'function') { | |
var params = []; | |
for (var i = 0, l = seriesArray.length; i < l; i++) { | |
data = seriesArray[i].data[dataIndex]; | |
value = this.getDataFromOption(data, '-'); | |
params.push({ | |
seriesIndex: seriesIndex[i], | |
seriesName: seriesArray[i].name || '', | |
series: seriesArray[i], | |
dataIndex: dataIndex, | |
data: data, | |
name: categoryAxis.getNameByIndex(dataIndex), | |
value: value, | |
// 向下兼容 | |
0: seriesArray[i].name || '', | |
1: categoryAxis.getNameByIndex(dataIndex), | |
2: value, | |
3: data | |
}); | |
} | |
this._curTicket = 'axis:' + dataIndex; | |
this._tDom.innerHTML = formatter.call( | |
this.myChart, params, this._curTicket, this._setContent | |
); | |
} | |
else if (typeof formatter === 'string') { | |
this._curTicket = NaN; | |
formatter = formatter.replace('{a}','{a0}') | |
.replace('{b}','{b0}') | |
.replace('{c}','{c0}'); | |
for (var i = 0, l = seriesArray.length; i < l; i++) { | |
formatter = formatter.replace( | |
'{a' + i + '}', | |
this._encodeHTML(seriesArray[i].name || '') | |
); | |
formatter = formatter.replace( | |
'{b' + i + '}', | |
this._encodeHTML(categoryAxis.getNameByIndex(dataIndex)) | |
); | |
data = seriesArray[i].data[dataIndex]; | |
data = this.getDataFromOption(data, '-'); | |
formatter = formatter.replace( | |
'{c' + i + '}', | |
data instanceof Array | |
? data : this.numAddCommas(data) | |
); | |
} | |
this._tDom.innerHTML = formatter; | |
} | |
else { | |
this._curTicket = NaN; | |
formatter = this._encodeHTML( | |
categoryAxis.getNameByIndex(dataIndex) | |
); | |
for (var i = 0, l = seriesArray.length; i < l; i++) { | |
formatter += '<br/>' | |
+ this._encodeHTML(seriesArray[i].name || '') | |
+ ' : '; | |
data = seriesArray[i].data[dataIndex]; | |
data = this.getDataFromOption(data, '-'); | |
formatter += data instanceof Array | |
? data : this.numAddCommas(data); | |
} | |
this._tDom.innerHTML = formatter; | |
} | |
} | |
// don't modify, just false, showContent == undefined == true | |
if (showContent === false || !this.option.tooltip.showContent) { | |
// 只用tooltip的行为,不显示主体 | |
return; | |
} | |
if (!this.hasAppend) { | |
this._tDom.style.left = this._zrWidth / 2 + 'px'; | |
this._tDom.style.top = this._zrHeight / 2 + 'px'; | |
this.dom.firstChild.appendChild(this._tDom); | |
this.hasAppend = true; | |
} | |
this._show(position, x + 10, y + 10, specialCssText); | |
} | |
}, | |
/** | |
* 极坐标 | |
*/ | |
_showPolarTrigger: function (polarIndex, dataIndex) { | |
if (this.component.polar == null | |
|| polarIndex == null | |
|| dataIndex == null | |
|| dataIndex < 0 | |
) { | |
return false; | |
} | |
var series = this.option.series; | |
var seriesArray = []; | |
var seriesIndex = []; | |
var formatter; | |
var position; | |
var showContent; | |
var specialCssText = ''; | |
if (this.option.tooltip.trigger === 'axis') { | |
if (!this.option.tooltip.show) { | |
return false; | |
} | |
formatter = this.option.tooltip.formatter; | |
position = this.option.tooltip.position; | |
} | |
var indicatorName = this.option.polar[polarIndex].indicator[dataIndex].text; | |
// 找到所有用这个极坐标并且axis触发的系列数据 | |
for (var i = 0, l = series.length; i < l; i++) { | |
if (!this._isSelected(series[i].name)) { | |
continue; | |
} | |
if (series[i].polarIndex === polarIndex | |
&& this.deepQuery([series[i], this.option], 'tooltip.trigger') === 'axis' | |
) { | |
showContent = this.query(series[i], 'tooltip.showContent') | |
|| showContent; | |
formatter = this.query(series[i], 'tooltip.formatter') | |
|| formatter; | |
position = this.query(series[i], 'tooltip.position') | |
|| position; | |
specialCssText += this._style(this.query(series[i], 'tooltip')); | |
seriesArray.push(series[i]); | |
seriesIndex.push(i); | |
} | |
} | |
if (seriesArray.length > 0) { | |
var polarData; | |
var data; | |
var value; | |
var params = []; | |
for (var i = 0, l = seriesArray.length; i < l; i++) { | |
polarData = seriesArray[i].data; | |
for (var j = 0, k = polarData.length; j < k; j++) { | |
data = polarData[j]; | |
if (!this._isSelected(data.name)) { | |
continue; | |
} | |
data = data != null | |
? data | |
: {name:'', value: {dataIndex:'-'}}; | |
value = this.getDataFromOption(data.value[dataIndex]); | |
params.push({ | |
seriesIndex: seriesIndex[i], | |
seriesName: seriesArray[i].name || '', | |
series: seriesArray[i], | |
dataIndex: dataIndex, | |
data: data, | |
name: data.name, | |
indicator: indicatorName, | |
value: value, | |
// 向下兼容 | |
0: seriesArray[i].name || '', | |
1: data.name, | |
2: value, | |
3: indicatorName | |
}); | |
} | |
} | |
if (params.length <= 0) { | |
return; | |
} | |
// 复位item trigger和axis trigger间短距离来回变换时的不响应 | |
this._lastItemTriggerId = -1; | |
// 相同dataIndex seriesIndex时不再触发内容更新 | |
if (this._lastDataIndex != dataIndex || this._lastSeriesIndex != seriesIndex[0]) { | |
this._lastDataIndex = dataIndex; | |
this._lastSeriesIndex = seriesIndex[0]; | |
if (typeof formatter === 'function') { | |
this._curTicket = 'axis:' + dataIndex; | |
this._tDom.innerHTML = formatter.call( | |
this.myChart, params, this._curTicket, this._setContent | |
); | |
} | |
else if (typeof formatter === 'string') { | |
formatter = formatter.replace('{a}','{a0}') | |
.replace('{b}','{b0}') | |
.replace('{c}','{c0}') | |
.replace('{d}','{d0}'); | |
for (var i = 0, l = params.length; i < l; i++) { | |
formatter = formatter.replace( | |
'{a' + i + '}', | |
this._encodeHTML(params[i].seriesName) | |
); | |
formatter = formatter.replace( | |
'{b' + i + '}', | |
this._encodeHTML(params[i].name) | |
); | |
formatter = formatter.replace( | |
'{c' + i + '}', | |
this.numAddCommas(params[i].value) | |
); | |
formatter = formatter.replace( | |
'{d' + i + '}', | |
this._encodeHTML(params[i].indicator) | |
); | |
} | |
this._tDom.innerHTML = formatter; | |
} | |
else { | |
formatter = this._encodeHTML(params[0].name) + '<br/>' | |
+ this._encodeHTML(params[0].indicator) + ' : ' | |
+ this.numAddCommas(params[0].value); | |
for (var i = 1, l = params.length; i < l; i++) { | |
formatter += '<br/>' + this._encodeHTML(params[i].name) | |
+ '<br/>'; | |
formatter += this._encodeHTML(params[i].indicator) + ' : ' | |
+ this.numAddCommas(params[i].value); | |
} | |
this._tDom.innerHTML = formatter; | |
} | |
} | |
// don't modify, just false, showContent == undefined == true | |
if (showContent === false || !this.option.tooltip.showContent) { | |
// 只用tooltip的行为,不显示主体 | |
return; | |
} | |
if (!this.hasAppend) { | |
this._tDom.style.left = this._zrWidth / 2 + 'px'; | |
this._tDom.style.top = this._zrHeight / 2 + 'px'; | |
this.dom.firstChild.appendChild(this._tDom); | |
this.hasAppend = true; | |
} | |
this._show( | |
position, | |
zrEvent.getX(this._event), | |
zrEvent.getY(this._event), | |
specialCssText | |
); | |
return true; | |
} | |
}, | |
/** | |
* @parma {boolean} axisTrigger | |
*/ | |
_showItemTrigger: function (axisTrigger) { | |
if (!this._curTarget) { | |
return; | |
} | |
var serie = ecData.get(this._curTarget, 'series'); | |
var seriesIndex = ecData.get(this._curTarget, 'seriesIndex'); | |
var data = ecData.get(this._curTarget, 'data'); | |
var dataIndex = ecData.get(this._curTarget, 'dataIndex'); | |
var name = ecData.get(this._curTarget, 'name'); | |
var value = ecData.get(this._curTarget, 'value'); | |
var special = ecData.get(this._curTarget, 'special'); | |
var special2 = ecData.get(this._curTarget, 'special2'); | |
var queryTarget = [data, serie, this.option]; | |
// 从低优先级往上找到trigger为item的formatter和样式 | |
var formatter; | |
var position; | |
var showContent; | |
var specialCssText = ''; | |
if (this._curTarget._type != 'island') { | |
// 全局 | |
var trigger = axisTrigger ? 'axis' : 'item'; | |
if (this.option.tooltip.trigger === trigger) { | |
formatter = this.option.tooltip.formatter; | |
position = this.option.tooltip.position; | |
} | |
// 系列 | |
if (this.query(serie, 'tooltip.trigger') === trigger) { | |
showContent = this.query(serie, 'tooltip.showContent') || showContent; | |
formatter = this.query(serie, 'tooltip.formatter') || formatter; | |
position = this.query(serie, 'tooltip.position') || position; | |
specialCssText += this._style(this.query(serie, 'tooltip')); | |
} | |
// 数据项 | |
showContent = this.query(data, 'tooltip.showContent') || showContent; | |
formatter = this.query(data, 'tooltip.formatter') || formatter; | |
position = this.query(data, 'tooltip.position') || position; | |
specialCssText += this._style(this.query(data, 'tooltip')); | |
} | |
else { | |
this._lastItemTriggerId = NaN; | |
showContent = this.deepQuery(queryTarget, 'tooltip.showContent'); | |
formatter = this.deepQuery(queryTarget, 'tooltip.islandFormatter'); | |
position = this.deepQuery(queryTarget, 'tooltip.islandPosition'); | |
} | |
// 复位item trigger和axis trigger间短距离来回变换时的不响应 | |
this._lastDataIndex = -1; | |
this._lastSeriesIndex = -1; | |
// 相同dataIndex seriesIndex时不再触发内容更新 | |
if (this._lastItemTriggerId !== this._curTarget.id) { | |
this._lastItemTriggerId = this._curTarget.id; | |
if (typeof formatter === 'function') { | |
this._curTicket = (serie.name || '') + ':' + dataIndex; | |
this._tDom.innerHTML = formatter.call( | |
this.myChart, | |
{ | |
seriesIndex: seriesIndex, | |
seriesName: serie.name || '', | |
series: serie, | |
dataIndex: dataIndex, | |
data: data, | |
name: name, | |
value: value, | |
percent: special, // 饼图 | |
indicator: special, // 雷达图 | |
value2: special2, | |
indicator2: special2, | |
// 向下兼容 | |
0: serie.name || '', | |
1: name, | |
2: value, | |
3: special, | |
4: special2, | |
5: data, | |
6: seriesIndex, | |
7: dataIndex | |
}, | |
this._curTicket, | |
this._setContent | |
); | |
} | |
else if (typeof formatter === 'string') { | |
this._curTicket = NaN; | |
formatter = formatter.replace('{a}', '{a0}') | |
.replace('{b}', '{b0}') | |
.replace('{c}', '{c0}'); | |
formatter = formatter.replace('{a0}', this._encodeHTML(serie.name || '')) | |
.replace('{b0}', this._encodeHTML(name)) | |
.replace( | |
'{c0}', | |
value instanceof Array ? value : this.numAddCommas(value) | |
); | |
formatter = formatter.replace('{d}', '{d0}') | |
.replace('{d0}', special || ''); | |
formatter = formatter.replace('{e}', '{e0}') | |
.replace( | |
'{e0}', | |
ecData.get(this._curTarget, 'special2') || '' | |
); | |
this._tDom.innerHTML = formatter; | |
} | |
else { | |
this._curTicket = NaN; | |
if (serie.type === ecConfig.CHART_TYPE_RADAR && special) { | |
this._tDom.innerHTML = this._itemFormatter.radar.call( | |
this, serie, name, value, special | |
); | |
} | |
// chord 处理暂时跟 force 一样 | |
// else if (serie.type === ecConfig.CHART_TYPE_CHORD) { | |
// this._tDom.innerHTML = this._itemFormatter.chord.call( | |
// this, serie, name, value, special, special2 | |
// ); | |
// } | |
else if (serie.type === ecConfig.CHART_TYPE_EVENTRIVER) { | |
this._tDom.innerHTML = this._itemFormatter.eventRiver.call( | |
this, serie, name, value, data | |
); | |
} | |
else { | |
this._tDom.innerHTML = '' | |
+ (serie.name != null ? (this._encodeHTML(serie.name) + '<br/>') : '') | |
+ (name === '' ? '' : (this._encodeHTML(name) + ' : ')) | |
+ (value instanceof Array ? value : this.numAddCommas(value)); | |
} | |
} | |
} | |
var x = zrEvent.getX(this._event); | |
var y = zrEvent.getY(this._event); | |
if (this.deepQuery(queryTarget, 'tooltip.axisPointer.show') | |
&& this.component.grid | |
) { | |
this._styleAxisPointer( | |
[serie], | |
this.component.grid.getX(), y, | |
this.component.grid.getXend(), y, | |
0, x, y | |
); | |
} | |
// don't modify, just false, showContent == undefined == true | |
if (showContent === false || !this.option.tooltip.showContent) { | |
// 只用tooltip的行为,不显示主体 | |
return; | |
} | |
if (!this.hasAppend) { | |
this._tDom.style.left = this._zrWidth / 2 + 'px'; | |
this._tDom.style.top = this._zrHeight / 2 + 'px'; | |
this.dom.firstChild.appendChild(this._tDom); | |
this.hasAppend = true; | |
} | |
this._show(position, x + 20, y - 20, specialCssText); | |
}, | |
_itemFormatter: { | |
radar: function(serie, name, value, indicator){ | |
var html = ''; | |
html += this._encodeHTML(name === '' ? (serie.name || '') : name); | |
html += html === '' ? '' : '<br />'; | |
for (var i = 0 ; i < indicator.length; i ++) { | |
html += this._encodeHTML(indicator[i].text) + ' : ' | |
+ this.numAddCommas(value[i]) + '<br />'; | |
} | |
return html; | |
}, | |
chord: function(serie, name, value, special, special2) { | |
if (special2 == null) { | |
// 外环上 | |
return this._encodeHTML(name) + ' (' + this.numAddCommas(value) + ')'; | |
} | |
else { | |
var name1 = this._encodeHTML(name); | |
var name2 = this._encodeHTML(special); | |
// 内部弦上 | |
return '' | |
+ (serie.name != null ? (this._encodeHTML(serie.name) + '<br/>') : '') | |
+ name1 + ' -> ' + name2 | |
+ ' (' + this.numAddCommas(value) + ')' | |
+ '<br />' | |
+ name2 + ' -> ' + name1 | |
+ ' (' + this.numAddCommas(special2) + ')'; | |
} | |
}, | |
eventRiver: function(serie, name, value, data) { | |
var html = ''; | |
html += this._encodeHTML(serie.name === '' ? '' : (serie.name + ' : ') ); | |
html += this._encodeHTML(name); | |
html += html === '' ? '' : '<br />'; | |
data = data.evolution; | |
for (var i = 0, l = data.length; i < l; i++) { | |
html += '<div style="padding-top:5px;">'; | |
if (!data[i].detail) { | |
continue; | |
} | |
if (data[i].detail.img) { | |
html += '<img src="' + data[i].detail.img | |
+ '" style="float:left;width:40px;height:40px;">'; | |
} | |
html += '<div style="margin-left:45px;">' + data[i].time + '<br/>'; | |
html += '<a href="' + data[i].detail.link + '" target="_blank">'; | |
html += data[i].detail.text + '</a></div>'; | |
html += '</div>'; | |
} | |
return html; | |
} | |
}, | |
/** | |
* 设置坐标轴指示器样式 | |
*/ | |
_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 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; | |
} | |
for (var i = 0, l = seriesArray.length; i < l; i++) { | |
//if (this.deepQuery([seriesArray[i], this.option], 'tooltip.trigger') === 'axis') { | |
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; | |
} | |
//} | |
} | |
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 | |
}; | |
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(); | |
} | |
}, | |
__onmousemove: function (param) { | |
clearTimeout(this._hidingTicket); | |
clearTimeout(this._showingTicket); | |
if (this._mousein && this._enterable) { | |
return; | |
} | |
var target = param.target; | |
var mx = zrEvent.getX(param.event); | |
var my = zrEvent.getY(param.event); | |
if (!target) { | |
// 判断是否落到直角系里,axis触发的tooltip | |
this._curTarget = false; | |
this._event = param.event; | |
// this._event._target = this._event.target || this._event.toElement; | |
this._event.zrenderX = mx; | |
this._event.zrenderY = my; | |
if (this._needAxisTrigger | |
&& this.component.grid | |
&& zrArea.isInside(rectangleInstance, this.component.grid.getArea(), mx, my) | |
) { | |
this._showingTicket = setTimeout(this._tryShow, this._showDelay); | |
} | |
else if (this._needAxisTrigger | |
&& this.component.polar | |
&& this.component.polar.isInside([mx, my]) != -1 | |
) { | |
this._showingTicket = setTimeout(this._tryShow, this._showDelay); | |
} | |
else { | |
!this._event.connectTrigger && this.messageCenter.dispatch( | |
ecConfig.EVENT.TOOLTIP_OUT_GRID, | |
this._event, | |
null, | |
this.myChart | |
); | |
this._hidingTicket = setTimeout(this._hide, this._hideDelay); | |
} | |
} | |
else { | |
this._curTarget = target; | |
this._event = param.event; | |
// this._event._target = this._event.target || this._event.toElement; | |
this._event.zrenderX = mx; | |
this._event.zrenderY = my; | |
var polarIndex; | |
if (this._needAxisTrigger | |
&& this.component.polar | |
&& (polarIndex = this.component.polar.isInside([mx, my])) != -1 | |
) { | |
// 看用这个polar的系列数据是否是axis触发,如果是设置_curTarget为nul | |
var series = this.option.series; | |
for (var i = 0, l = series.length; i < l; i++) { | |
if (series[i].polarIndex === polarIndex | |
&& this.deepQuery( | |
[series[i], this.option], 'tooltip.trigger' | |
) === 'axis' | |
) { | |
this._curTarget = null; | |
break; | |
} | |
} | |
} | |
this._showingTicket = setTimeout(this._tryShow, this._showDelay); | |
} | |
}, | |
/** | |
* zrender事件响应:鼠标离开绘图区域 | |
*/ | |
__onglobalout: function () { | |
clearTimeout(this._hidingTicket); | |
clearTimeout(this._showingTicket); | |
this._hidingTicket = setTimeout(this._hide, this._hideDelay); | |
}, | |
/** | |
* 异步回调填充内容 | |
*/ | |
__setContent: function (ticket, content) { | |
if (!this._tDom) { | |
return; | |
} | |
if (ticket === this._curTicket) { | |
this._tDom.innerHTML = content; | |
} | |
setTimeout(this._refixed, 20); | |
}, | |
ontooltipHover: function (param, tipShape) { | |
if (!this._lastTipShape // 不存在或者存在但dataIndex发生变化才需要重绘 | |
|| (this._lastTipShape && this._lastTipShape.dataIndex != param.dataIndex) | |
) { | |
if (this._lastTipShape && this._lastTipShape.tipShape.length > 0) { | |
this.zr.delShape(this._lastTipShape.tipShape); | |
this.shapeList.length = 2; | |
} | |
for (var i = 0, l = tipShape.length; i < l; i++) { | |
tipShape[i].zlevel = this.getZlevelBase(); | |
tipShape[i].z = this.getZBase(); | |
tipShape[i].style = zrShapeBase.prototype.getHighlightStyle( | |
tipShape[i].style, | |
tipShape[i].highlightStyle | |
); | |
tipShape[i].draggable = false; | |
tipShape[i].hoverable = false; | |
tipShape[i].clickable = false; | |
tipShape[i].ondragend = null; | |
tipShape[i].ondragover = null; | |
tipShape[i].ondrop = null; | |
this.shapeList.push(tipShape[i]); | |
this.zr.addShape(tipShape[i]); | |
} | |
this._lastTipShape = { | |
dataIndex: param.dataIndex, | |
tipShape: tipShape | |
}; | |
} | |
}, | |
ondragend: function () { | |
this._hide(); | |
}, | |
/** | |
* 图例选择 | |
*/ | |
onlegendSelected: function (param) { | |
this._selectedMap = param.selected; | |
}, | |
_setSelectedMap: function () { | |
if (this.component.legend) { | |
this._selectedMap = zrUtil.clone(this.component.legend.getSelectedMap()); | |
} | |
else { | |
this._selectedMap = {}; | |
} | |
}, | |
_isSelected: function (itemName) { | |
if (this._selectedMap[itemName] != null) { | |
return this._selectedMap[itemName]; | |
} | |
else { | |
return true; // 没在legend里定义的都为true啊~ | |
} | |
}, | |
/** | |
* 模拟tooltip hover方法 | |
* {object} params 参数 | |
* {seriesIndex: 0, seriesName:'', dataInex:0} line、bar、scatter、k、radar | |
* {seriesIndex: 0, seriesName:'', name:''} map、pie、chord | |
*/ | |
showTip: function (params) { | |
if (!params) { | |
return; | |
} | |
var seriesIndex; | |
var series = this.option.series; | |
if (params.seriesIndex != null) { | |
seriesIndex = params.seriesIndex; | |
} | |
else { | |
var seriesName = params.seriesName; | |
for (var i = 0, l = series.length; i < l; i++) { | |
if (series[i].name === seriesName) { | |
seriesIndex = i; | |
break; | |
} | |
} | |
} | |
var serie = series[seriesIndex]; | |
if (serie == null) { | |
return; | |
} | |
var chart = this.myChart.chart[serie.type]; | |
var isAxisTrigger = this.deepQuery( | |
[serie, this.option], 'tooltip.trigger' | |
) === 'axis'; | |
if (!chart) { | |
return; | |
} | |
if (isAxisTrigger) { | |
// axis trigger | |
var dataIndex = params.dataIndex; | |
switch (chart.type) { | |
case ecConfig.CHART_TYPE_LINE : | |
case ecConfig.CHART_TYPE_BAR : | |
case ecConfig.CHART_TYPE_K : | |
if (this.component.xAxis == null | |
|| this.component.yAxis == null | |
|| serie.data.length <= dataIndex | |
) { | |
return; | |
} | |
var xAxisIndex = serie.xAxisIndex || 0; | |
var yAxisIndex = serie.yAxisIndex || 0; | |
if (this.component.xAxis.getAxis(xAxisIndex).type | |
=== ecConfig.COMPONENT_TYPE_AXIS_CATEGORY | |
) { | |
// 横轴是类目 | |
this._event = { | |
zrenderX: this.component.xAxis.getAxis(xAxisIndex) | |
.getCoordByIndex(dataIndex), | |
zrenderY: this.component.grid.getY() | |
+ (this.component.grid.getYend() | |
- this.component.grid.getY() | |
) / 4 | |
}; | |
} | |
else { | |
// 纵轴是类目 | |
this._event = { | |
zrenderX: this.component.grid.getX() | |
+ (this.component.grid.getXend() | |
- this.component.grid.getX() | |
) / 4, | |
zrenderY: this.component.yAxis.getAxis(yAxisIndex) | |
.getCoordByIndex(dataIndex) | |
}; | |
} | |
this._showAxisTrigger( | |
xAxisIndex, | |
yAxisIndex, | |
dataIndex | |
); | |
break; | |
case ecConfig.CHART_TYPE_RADAR : | |
if (this.component.polar == null | |
|| serie.data[0].value.length <= dataIndex | |
) { | |
return; | |
} | |
var polarIndex = serie.polarIndex || 0; | |
var vector = this.component.polar.getVector( | |
polarIndex, dataIndex, 'max' | |
); | |
this._event = { | |
zrenderX: vector[0], | |
zrenderY: vector[1] | |
}; | |
this._showPolarTrigger( | |
polarIndex, | |
dataIndex | |
); | |
break; | |
} | |
} | |
else { | |
// item trigger | |
var shapeList = chart.shapeList; | |
var x; | |
var y; | |
switch (chart.type) { | |
case ecConfig.CHART_TYPE_LINE : | |
case ecConfig.CHART_TYPE_BAR : | |
case ecConfig.CHART_TYPE_K : | |
case ecConfig.CHART_TYPE_SCATTER : | |
var dataIndex = params.dataIndex; | |
for (var i = 0, l = shapeList.length; i < l; i++) { | |
if (shapeList[i]._mark == null | |
&& ecData.get(shapeList[i], 'seriesIndex') == seriesIndex | |
&& ecData.get(shapeList[i], 'dataIndex') == dataIndex | |
) { | |
this._curTarget = shapeList[i]; | |
x = shapeList[i].style.x; | |
y = chart.type != ecConfig.CHART_TYPE_K | |
? shapeList[i].style.y : shapeList[i].style.y[0]; | |
break; | |
} | |
} | |
break; | |
case ecConfig.CHART_TYPE_RADAR : | |
var dataIndex = params.dataIndex; | |
for (var i = 0, l = shapeList.length; i < l; i++) { | |
if (shapeList[i].type === 'polygon' | |
&& ecData.get(shapeList[i], 'seriesIndex') == seriesIndex | |
&& ecData.get(shapeList[i], 'dataIndex') == dataIndex | |
) { | |
this._curTarget = shapeList[i]; | |
var vector = this.component.polar.getCenter( | |
serie.polarIndex || 0 | |
); | |
x = vector[0]; | |
y = vector[1]; | |
break; | |
} | |
} | |
break; | |
case ecConfig.CHART_TYPE_PIE : | |
var name = params.name; | |
for (var i = 0, l = shapeList.length; i < l; i++) { | |
if (shapeList[i].type === 'sector' | |
&& ecData.get(shapeList[i], 'seriesIndex') == seriesIndex | |
&& ecData.get(shapeList[i], 'name') == name | |
) { | |
this._curTarget = shapeList[i]; | |
var style = this._curTarget.style; | |
var midAngle = (style.startAngle + style.endAngle) | |
/ 2 * Math.PI / 180; | |
x = this._curTarget.style.x + Math.cos(midAngle) * style.r / 1.5; | |
y = this._curTarget.style.y - Math.sin(midAngle) * style.r / 1.5; | |
break; | |
} | |
} | |
break; | |
case ecConfig.CHART_TYPE_MAP : | |
var name = params.name; | |
var mapType = serie.mapType; | |
for (var i = 0, l = shapeList.length; i < l; i++) { | |
if (shapeList[i].type === 'text' | |
&& shapeList[i]._mapType === mapType | |
&& shapeList[i].style._name === name | |
) { | |
this._curTarget = shapeList[i]; | |
x = this._curTarget.style.x + this._curTarget.position[0]; | |
y = this._curTarget.style.y + this._curTarget.position[1]; | |
break; | |
} | |
} | |
break; | |
case ecConfig.CHART_TYPE_CHORD: | |
var name = params.name; | |
for (var i = 0, l = shapeList.length; i < l; i++) { | |
if (shapeList[i].type === 'sector' | |
&& ecData.get(shapeList[i], 'name') == name | |
) { | |
this._curTarget = shapeList[i]; | |
var style = this._curTarget.style; | |
var midAngle = (style.startAngle + style.endAngle) | |
/ 2 * Math.PI / 180; | |
x = this._curTarget.style.x + Math.cos(midAngle) * (style.r - 2); | |
y = this._curTarget.style.y - Math.sin(midAngle) * (style.r - 2); | |
this.zr.trigger( | |
zrConfig.EVENT.MOUSEMOVE, | |
{ | |
zrenderX: x, | |
zrenderY: y | |
} | |
); | |
return; | |
} | |
} | |
break; | |
case ecConfig.CHART_TYPE_FORCE: | |
var name = params.name; | |
for (var i = 0, l = shapeList.length; i < l; i++) { | |
if (shapeList[i].type === 'circle' | |
&& ecData.get(shapeList[i], 'name') == name | |
) { | |
this._curTarget = shapeList[i]; | |
x = this._curTarget.position[0]; | |
y = this._curTarget.position[1]; | |
break; | |
} | |
} | |
break; | |
} | |
if (x != null && y != null) { | |
this._event = { | |
zrenderX: x, | |
zrenderY: y | |
}; | |
this.zr.addHoverShape(this._curTarget); | |
this.zr.refreshHover(); | |
this._showItemTrigger(); | |
} | |
} | |
}, | |
/** | |
* 关闭,公开接口 | |
*/ | |
hideTip: function () { | |
this._hide(); | |
}, | |
/** | |
* 刷新 | |
*/ | |
refresh: function (newOption) { | |
// this._selectedMap; | |
// this._defaultCssText; // css样式缓存 | |
// this._needAxisTrigger; // 坐标轴触发 | |
// this._curTarget; | |
// this._event; | |
// this._curTicket; // 异步回调标识,用来区分多个请求 | |
// 缓存一些高宽数据 | |
this._zrHeight = this.zr.getHeight(); | |
this._zrWidth = this.zr.getWidth(); | |
if (this._lastTipShape && this._lastTipShape.tipShape.length > 0) { | |
this.zr.delShape(this._lastTipShape.tipShape); | |
} | |
this._lastTipShape = false; | |
this.shapeList.length = 2; | |
this._lastDataIndex = -1; | |
this._lastSeriesIndex = -1; | |
this._lastItemTriggerId = -1; | |
if (newOption) { | |
this.option = newOption; | |
this.option.tooltip = this.reformOption(this.option.tooltip); | |
this.option.tooltip.textStyle = zrUtil.merge( | |
this.option.tooltip.textStyle, | |
this.ecTheme.textStyle | |
); | |
this._needAxisTrigger = false; | |
if (this.option.tooltip.trigger === 'axis') { | |
this._needAxisTrigger = true; | |
} | |
var series = this.option.series; | |
for (var i = 0, l = series.length; i < l; i++) { | |
if (this.query(series[i], 'tooltip.trigger') === 'axis') { | |
this._needAxisTrigger = true; | |
break; | |
} | |
} | |
// this._hidingTicket; | |
// this._showingTicket; | |
this._showDelay = this.option.tooltip.showDelay; // 显示延迟 | |
this._hideDelay = this.option.tooltip.hideDelay; // 隐藏延迟 | |
this._defaultCssText = this._style(this.option.tooltip); | |
this._setSelectedMap(); | |
this._axisLineWidth = this.option.tooltip.axisPointer.lineStyle.width; | |
this._enterable = this.option.tooltip.enterable; | |
} | |
if (this.showing) { | |
var self = this; | |
setTimeout(function(){ | |
self.zr.trigger(zrConfig.EVENT.MOUSEMOVE, self.zr.handler._event); | |
},50); | |
} | |
}, | |
/** | |
* 释放后实例不可用,重载基类方法 | |
*/ | |
onbeforDispose: function () { | |
if (this._lastTipShape && this._lastTipShape.tipShape.length > 0) { | |
this.zr.delShape(this._lastTipShape.tipShape); | |
} | |
clearTimeout(this._hidingTicket); | |
clearTimeout(this._showingTicket); | |
this.zr.un(zrConfig.EVENT.MOUSEMOVE, this._onmousemove); | |
this.zr.un(zrConfig.EVENT.GLOBALOUT, this._onglobalout); | |
if (this.hasAppend && !!this.dom.firstChild) { | |
this.dom.firstChild.removeChild(this._tDom); | |
} | |
this._tDom = null; | |
}, | |
/** | |
* html转码的方法 | |
*/ | |
_encodeHTML: function (source) { | |
return String(source) | |
.replace(/&/g, '&') | |
.replace(/</g, '<') | |
.replace(/>/g, '>') | |
.replace(/"/g, '"') | |
.replace(/'/g, '''); | |
} | |
}; | |
zrUtil.inherits(Tooltip, Base); | |
require('../component').define('tooltip', Tooltip); | |
return Tooltip; | |
}); |