/**
* 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}
{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 += '
'
+ 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) + '
'
+ this._encodeHTML(params[0].indicator) + ' : '
+ this.numAddCommas(params[0].value);
for (var i = 1, l = params.length; i < l; i++) {
formatter += '
' + this._encodeHTML(params[i].name)
+ '
';
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) + '
') : '')
+ (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
);
}
else {
this._hide();
}
// 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 === '' ? '' : '
';
for (var i = 0 ; i < indicator.length; i ++) {
html += this._encodeHTML(indicator[i].text) + ' : '
+ this.numAddCommas(value[i]) + '
';
}
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) + '
') : '')
+ name1 + ' -> ' + name2
+ ' (' + this.numAddCommas(value) + ')'
+ '
'
+ 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 === '' ? '' : '
';
data = data.evolution;
for (var i = 0, l = data.length; i < l; i++) {
html += '