/** | |
* echarts组件:提示框 | |
* | |
* @desc echarts基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据统计图表。 | |
* @author Kener (@Kener-林峰, linzhifeng@baidu.com) | |
* | |
*/ | |
define(function (require) { | |
/** | |
* 构造函数 | |
* @param {Object} messageCenter echart消息中心 | |
* @param {ZRender} zr zrender实例 | |
* @param {Object} option 提示框参数 | |
* @param {HtmlElement} dom 目标对象 | |
*/ | |
function Tooltip(messageCenter, zr, option, dom) { | |
var Base = require('./base'); | |
Base.call(this, zr); | |
var ecConfig = require('../config'); | |
var ecData = require('../util/ecData'); | |
var zrConfig = require('zrender/config'); | |
var zrShape = require('zrender/shape'); | |
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 rectangle = zrShape.get('rectangle'); | |
var self = this; | |
self.type = ecConfig.COMPONENT_TYPE_TOOLTIP; | |
var _zlevelBase = self.getZlevelBase(); | |
var component = {}; // 组件索引 | |
var grid; | |
var xAxis; | |
var yAxis; | |
var polar; | |
// tooltip dom & css | |
var _tDom = document.createElement('div'); | |
// 通用样式 | |
var _gCssText = 'position:absolute;' | |
+ 'display:block;' | |
+ 'border-style:solid;' | |
+ 'white-space:nowrap;'; | |
// 默认样式 | |
var _defaultCssText; // css样式缓存 | |
var _needAxisTrigger; // 坐标轴触发 | |
var _hidingTicket; | |
var _hideDelay; // 隐藏延迟 | |
var _showingTicket; | |
var _showDelay; // 显示延迟 | |
var _curTarget; | |
var _event; | |
var _curTicket; // 异步回调标识,用来区分多个请求 | |
// 缓存一些高宽数据 | |
var _zrHeight = zr.getHeight(); | |
var _zrWidth = zr.getWidth(); | |
var _axisLineShape = { | |
shape : 'line', | |
id : zr.newShapeId('tooltip'), | |
zlevel: _zlevelBase, | |
invisible : true, | |
hoverable: false, | |
style : { | |
// lineWidth : 2, | |
// strokeColor : ecConfig.categoryAxis.axisLine.lineStyle.color | |
} | |
}; | |
var _axisShadowShape = { | |
shape : 'line', | |
id : zr.newShapeId('tooltip'), | |
zlevel: 1, // grid上,chart下 | |
invisible : true, | |
hoverable: false, | |
style : { | |
// lineWidth : 10, | |
// strokeColor : ecConfig.categoryAxis.axisLine.lineStyle.color | |
} | |
}; | |
zr.addShape(_axisLineShape); | |
zr.addShape(_axisShadowShape); | |
/** | |
* 根据配置设置dom样式 | |
*/ | |
function _style(opt) { | |
if (!opt) { | |
return ''; | |
} | |
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 (typeof opt.borderWidth != 'undefined') { | |
cssText.push('border-width:' + opt.borderWidth + 'px'); | |
} | |
if (typeof opt.borderColor != 'undefined') { | |
cssText.push('border-color:' + opt.borderColor); | |
} | |
if (typeof opt.borderRadius != 'undefined') { | |
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 (typeof padding != 'undefined') { | |
padding = self.reformCssArray(padding); | |
cssText.push( | |
'padding:' + padding[0] + 'px ' | |
+ padding[1] + 'px ' | |
+ padding[2] + 'px ' | |
+ padding[3] + 'px' | |
); | |
} | |
cssText = cssText.join(';') + ';'; | |
return cssText; | |
} | |
function _hide() { | |
if (_tDom) { | |
_tDom.style.display = 'none'; | |
} | |
var needRefresh = false; | |
if (!_axisLineShape.invisible) { | |
_axisLineShape.invisible = true; | |
zr.modShape(_axisLineShape.id, _axisLineShape); | |
needRefresh = true; | |
} | |
if (!_axisShadowShape.invisible) { | |
_axisShadowShape.invisible = true; | |
zr.modShape(_axisShadowShape.id, _axisShadowShape); | |
needRefresh = true; | |
} | |
needRefresh && zr.refresh(); | |
} | |
function _show(x, y, specialCssText) { | |
var domHeight = _tDom.offsetHeight; | |
var domWidth = _tDom.offsetWidth; | |
if (x + domWidth > _zrWidth) { | |
x = _zrWidth - domWidth; | |
} | |
if (y + domHeight > _zrHeight) { | |
y = _zrHeight - domHeight; | |
} | |
if (y < 20) { | |
y = 0; | |
} | |
_tDom.style.cssText = _gCssText | |
+ _defaultCssText | |
+ (specialCssText ? specialCssText : '') | |
+ 'left:' + x + 'px;top:' + y + 'px;'; | |
if (_zrWidth - x < 100 || _zrHeight - y < 100) { | |
// 太靠边的做一次refixed | |
setTimeout(_refixed, 20); | |
} | |
} | |
function _refixed() { | |
if (_tDom) { | |
var cssText = ''; | |
var domHeight = _tDom.offsetHeight; | |
var domWidth = _tDom.offsetWidth; | |
if (_tDom.offsetLeft + domWidth > _zrWidth) { | |
cssText += 'left:' + (_zrWidth - domWidth) + 'px;'; | |
} | |
if (_tDom.offsetTop + domHeight > _zrHeight) { | |
cssText += 'top:' + (_zrHeight - domHeight) + 'px;'; | |
} | |
if (cssText !== '') { | |
_tDom.style.cssText += cssText; | |
} | |
} | |
} | |
function _tryShow() { | |
var needShow; | |
var trigger; | |
if (!_curTarget) { | |
// 坐标轴事件 | |
_findPolarTrigger() || _findAxisTrigger(); | |
} | |
else { | |
// 数据项事件 | |
if (_curTarget._type == 'island' | |
&& self.deepQuery([option], 'tooltip.show') | |
) { | |
_showItemTrigger(); | |
return; | |
} | |
var serie = ecData.get(_curTarget, 'series'); | |
var data = ecData.get(_curTarget, 'data'); | |
needShow = self.deepQuery( | |
[data, serie, option], | |
'tooltip.show' | |
); | |
if (typeof serie == 'undefined' | |
|| typeof data == 'undefined' | |
|| needShow === false | |
) { | |
// 不响应tooltip的数据对象延时隐藏 | |
clearTimeout(_hidingTicket); | |
clearTimeout(_showingTicket); | |
_hidingTicket = setTimeout(_hide, _hideDelay); | |
} | |
else { | |
trigger = self.deepQuery( | |
[data, serie, option], | |
'tooltip.trigger' | |
); | |
trigger == 'axis' | |
? _showAxisTrigger( | |
serie.xAxisIndex, serie.yAxisIndex, | |
ecData.get(_curTarget, 'dataIndex') | |
) | |
: _showItemTrigger(); | |
} | |
} | |
} | |
/** | |
* 直角系 | |
*/ | |
function _findAxisTrigger() { | |
if (!xAxis || !yAxis) { | |
_hidingTicket = setTimeout(_hide, _hideDelay); | |
return; | |
} | |
var series = option.series; | |
var xAxisIndex; | |
var yAxisIndex; | |
for (var i = 0, l = series.length; i < l; i++) { | |
// 找到第一个axis触发tooltip的系列 | |
if (self.deepQuery( | |
[series[i], option], 'tooltip.trigger' | |
) == 'axis' | |
) { | |
xAxisIndex = series[i].xAxisIndex || 0; | |
yAxisIndex = series[i].yAxisIndex || 0; | |
if (xAxis.getAxis(xAxisIndex) | |
&& xAxis.getAxis(xAxisIndex).type | |
== ecConfig.COMPONENT_TYPE_AXIS_CATEGORY | |
) { | |
// 横轴为类目轴 | |
_showAxisTrigger(xAxisIndex, yAxisIndex, | |
_getNearestDataIndex('x', xAxis.getAxis(xAxisIndex)) | |
); | |
return; | |
} else if (yAxis.getAxis(yAxisIndex) | |
&& yAxis.getAxis(yAxisIndex).type | |
== ecConfig.COMPONENT_TYPE_AXIS_CATEGORY | |
) { | |
// 纵轴为类目轴 | |
_showAxisTrigger(xAxisIndex, yAxisIndex, | |
_getNearestDataIndex('y', yAxis.getAxis(yAxisIndex)) | |
); | |
return; | |
} | |
} | |
} | |
} | |
/** | |
* 极坐标 | |
*/ | |
function _findPolarTrigger() { | |
if (!polar) { | |
return false; | |
} | |
var x = zrEvent.getX(_event); | |
var y = zrEvent.getY(_event); | |
var polarIndex = polar.getNearestIndex([x, y]); | |
var valueIndex; | |
if (polarIndex) { | |
valueIndex = polarIndex.valueIndex; | |
polarIndex = polarIndex.polarIndex; | |
} | |
else { | |
polarIndex = -1; | |
} | |
if (polarIndex != -1) { | |
return _showPolarTrigger(polarIndex, valueIndex); | |
} | |
return false; | |
} | |
/** | |
* 根据坐标轴事件带的属性获取最近的axisDataIndex | |
*/ | |
function _getNearestDataIndex(direction, categoryAxis) { | |
var dataIndex = -1; | |
var x = zrEvent.getX(_event); | |
var y = zrEvent.getY(_event); | |
if (direction == 'x') { | |
// 横轴为类目轴 | |
var left; | |
var right; | |
var xEnd = grid.getXend(); | |
var curCoord = categoryAxis.getCoordByIndex(dataIndex); | |
while (curCoord < xEnd) { | |
if (curCoord <= x) { | |
left = curCoord; | |
} | |
if (curCoord >= x) { | |
break; | |
} | |
curCoord = categoryAxis.getCoordByIndex(++dataIndex); | |
right = curCoord; | |
} | |
if (x - left < right - x) { | |
dataIndex -= 1; | |
} | |
else { | |
// 离右边近,看是否为最后一个 | |
if (typeof categoryAxis.getNameByIndex(dataIndex) | |
== 'undefined' | |
) { | |
dataIndex = -1; | |
} | |
} | |
return dataIndex; | |
} | |
else { | |
// 纵轴为类目轴 | |
var top; | |
var bottom; | |
var yStart = grid.getY(); | |
var curCoord = categoryAxis.getCoordByIndex(dataIndex); | |
while (curCoord > yStart) { | |
if (curCoord >= y) { | |
bottom = curCoord; | |
} | |
if (curCoord <= y) { | |
break; | |
} | |
curCoord = categoryAxis.getCoordByIndex(++dataIndex); | |
top = curCoord; | |
} | |
if (y - top > bottom - y) { | |
dataIndex -= 1; | |
} | |
else { | |
// 离上方边近,看是否为最后一个 | |
if (typeof categoryAxis.getNameByIndex(dataIndex) | |
== 'undefined' | |
) { | |
dataIndex = -1; | |
} | |
} | |
return dataIndex; | |
} | |
return -1; | |
} | |
/** | |
* 直角系 | |
*/ | |
function _showAxisTrigger(xAxisIndex, yAxisIndex, dataIndex) { | |
if (typeof xAxis == 'undefined' | |
|| typeof yAxis == 'undefined' | |
|| typeof xAxisIndex == 'undefined' | |
|| typeof yAxisIndex == 'undefined' | |
|| dataIndex < 0 | |
) { | |
// 不响应tooltip的数据对象延时隐藏 | |
clearTimeout(_hidingTicket); | |
clearTimeout(_showingTicket); | |
_hidingTicket = setTimeout(_hide, _hideDelay); | |
return; | |
} | |
var series = option.series; | |
var seriesArray = []; | |
var categoryAxis; | |
var x; | |
var y; | |
var formatter; | |
var specialCssText = ''; | |
if (self.deepQuery([option], 'tooltip.trigger') == 'axis') { | |
if (self.deepQuery([option], 'tooltip.show') === false) { | |
return; | |
} | |
formatter = self.deepQuery([option],'tooltip.formatter'); | |
} | |
if (xAxisIndex != -1 | |
&& xAxis.getAxis(xAxisIndex).type | |
== ecConfig.COMPONENT_TYPE_AXIS_CATEGORY | |
) { | |
// 横轴为类目轴,找到所有用这条横轴并且axis触发的系列数据 | |
categoryAxis = xAxis.getAxis(xAxisIndex); | |
for (var i = 0, l = series.length; i < l; i++) { | |
if (series[i].xAxisIndex == xAxisIndex | |
&& self.deepQuery( | |
[series[i], option], 'tooltip.trigger' | |
) == 'axis' | |
) { | |
formatter = self.deepQuery( | |
[series[i]], | |
'tooltip.formatter' | |
) || formatter; | |
specialCssText += _style(self.deepQuery( | |
[series[i]], 'tooltip' | |
)); | |
seriesArray.push(series[i]); | |
} | |
} | |
y = zrEvent.getY(_event) + 10; | |
x = categoryAxis.getCoordByIndex(dataIndex); | |
_styleAxisPointer( | |
seriesArray, | |
x, grid.getY(), | |
x, grid.getYend(), | |
categoryAxis.getGap() | |
); | |
x += 10; | |
} | |
else if (yAxisIndex != -1 | |
&& yAxis.getAxis(yAxisIndex).type | |
== ecConfig.COMPONENT_TYPE_AXIS_CATEGORY | |
) { | |
// 纵轴为类目轴,找到所有用这条纵轴并且axis触发的系列数据 | |
categoryAxis = yAxis.getAxis(yAxisIndex); | |
for (var i = 0, l = series.length; i < l; i++) { | |
if (series[i].yAxisIndex == yAxisIndex | |
&& self.deepQuery( | |
[series[i], option], 'tooltip.trigger' | |
) == 'axis' | |
) { | |
formatter = self.deepQuery( | |
[series[i]], | |
'tooltip.formatter' | |
) || formatter; | |
specialCssText += _style(self.deepQuery( | |
[series[i]], 'tooltip' | |
)); | |
seriesArray.push(series[i]); | |
} | |
} | |
x = zrEvent.getX(_event) + 10; | |
y = categoryAxis.getCoordByIndex(dataIndex); | |
_styleAxisPointer( | |
seriesArray, | |
grid.getX(), y, | |
grid.getXend(), y, | |
categoryAxis.getGap() | |
); | |
y += 10; | |
} | |
if (seriesArray.length > 0) { | |
var data; | |
if (typeof formatter == 'function') { | |
var params = []; | |
for (var i = 0, l = seriesArray.length; i < l; i++) { | |
data = seriesArray[i].data[dataIndex]; | |
data = typeof data != 'undefined' | |
? (typeof data.value != 'undefined' | |
? data.value | |
: data) | |
: '-'; | |
params.push([ | |
seriesArray[i].name, | |
categoryAxis.getNameByIndex(dataIndex), | |
data | |
]); | |
} | |
_curTicket = 'axis:' + dataIndex; | |
_tDom.innerHTML = formatter( | |
params, _curTicket, _setContent | |
); | |
} | |
else if (typeof formatter == 'string') { | |
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 + '}', | |
seriesArray[i].name | |
); | |
formatter = formatter.replace( | |
'{b' + i + '}', | |
categoryAxis.getNameByIndex(dataIndex) | |
); | |
data = seriesArray[i].data[dataIndex]; | |
data = typeof data != 'undefined' | |
? (typeof data.value != 'undefined' | |
? data.value | |
: data) | |
: '-'; | |
formatter = formatter.replace( | |
'{c' + i + '}', | |
data | |
); | |
} | |
_tDom.innerHTML = formatter; | |
} | |
else { | |
formatter = categoryAxis.getNameByIndex(dataIndex); | |
for (var i = 0, l = seriesArray.length; i < l; i++) { | |
formatter += '<br/>' + seriesArray[i].name + ' : '; | |
data = seriesArray[i].data[dataIndex]; | |
data = data = typeof data != 'undefined' | |
? (typeof data.value != 'undefined' | |
? data.value | |
: data) | |
: '-'; | |
formatter += data; | |
} | |
_tDom.innerHTML = formatter; | |
} | |
if (!self.hasAppend) { | |
_tDom.style.left = _zrWidth / 2 + 'px'; | |
_tDom.style.top = _zrHeight / 2 + 'px'; | |
dom.firstChild.appendChild(_tDom); | |
self.hasAppend = true; | |
} | |
_show(x, y, specialCssText); | |
} | |
} | |
/** | |
* 极坐标 | |
*/ | |
function _showPolarTrigger(polarIndex, dataIndex) { | |
if (typeof polar == 'undefined' | |
|| typeof polarIndex == 'undefined' | |
|| typeof dataIndex == 'undefined' | |
|| dataIndex < 0 | |
) { | |
return false; | |
} | |
var series = option.series; | |
var seriesArray = []; | |
var formatter; | |
var specialCssText = ''; | |
if (self.deepQuery([option], 'tooltip.trigger') == 'axis') { | |
if (self.deepQuery([option], 'tooltip.show') === false) { | |
return false; | |
} | |
formatter = self.deepQuery([option],'tooltip.formatter'); | |
} | |
// 找到所有用这个极坐标并且axis触发的系列数据 | |
for (var i = 0, l = series.length; i < l; i++) { | |
if (series[i].polarIndex == polarIndex | |
&& self.deepQuery( | |
[series[i], option], 'tooltip.trigger' | |
) == 'axis' | |
) { | |
formatter = self.deepQuery( | |
[series[i]], | |
'tooltip.formatter' | |
) || formatter; | |
specialCssText += _style(self.deepQuery( | |
[series[i]], 'tooltip' | |
)); | |
seriesArray.push(series[i]); | |
} | |
} | |
if (seriesArray.length > 0) { | |
var polarData; | |
var data; | |
var params = []; | |
var indicatorName = | |
option.polar[polarIndex].indicator[dataIndex].text; | |
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]; | |
data = typeof data != 'undefined' | |
? data | |
: {name:'', value: {dataIndex:'-'}}; | |
params.push([ | |
typeof seriesArray[i].name != 'undefin' | |
? seriesArray[i].name : '', | |
data.name, | |
data.value[dataIndex], | |
indicatorName | |
]); | |
} | |
} | |
if (typeof formatter == 'function') { | |
_curTicket = 'axis:' + dataIndex; | |
_tDom.innerHTML = formatter( | |
params, _curTicket, _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 + '}', | |
params[i][0] | |
); | |
formatter = formatter.replace( | |
'{b' + i + '}', | |
params[i][1] | |
); | |
formatter = formatter.replace( | |
'{c' + i + '}', | |
params[i][2] | |
); | |
formatter = formatter.replace( | |
'{d' + i + '}', | |
params[i][3] | |
); | |
} | |
_tDom.innerHTML = formatter; | |
} | |
else { | |
formatter = params[0][1] + '<br/>' | |
+ params[0][3] + ' : ' + params[0][2]; | |
for (var i = 1, l = params.length; i < l; i++) { | |
formatter += '<br/>' + params[i][1] + '<br/>'; | |
formatter += params[i][3] + ' : ' + params[i][2]; | |
} | |
_tDom.innerHTML = formatter; | |
} | |
if (!self.hasAppend) { | |
_tDom.style.left = _zrWidth / 2 + 'px'; | |
_tDom.style.top = _zrHeight / 2 + 'px'; | |
dom.firstChild.appendChild(_tDom); | |
self.hasAppend = true; | |
} | |
_show( | |
zrEvent.getX(_event), | |
zrEvent.getY(_event), | |
specialCssText | |
); | |
return true; | |
} | |
} | |
function _showItemTrigger() { | |
var serie = ecData.get(_curTarget, 'series'); | |
var data = ecData.get(_curTarget, 'data'); | |
var name = ecData.get(_curTarget, 'name'); | |
var value = ecData.get(_curTarget, 'value'); | |
var speical = ecData.get(_curTarget, 'special'); | |
// 从低优先级往上找到trigger为item的formatter和样式 | |
var formatter; | |
var specialCssText = ''; | |
var indicator; | |
var html = ''; | |
if (_curTarget._type != 'island') { | |
// 全局 | |
if (self.deepQuery([option], 'tooltip.trigger') == 'item' | |
) { | |
formatter = self.deepQuery( | |
[option], 'tooltip.formatter' | |
) || formatter; | |
} | |
// 系列 | |
if (self.deepQuery([serie], 'tooltip.trigger') == 'item' | |
) { | |
formatter = self.deepQuery( | |
[serie], 'tooltip.formatter' | |
) || formatter; | |
specialCssText += _style(self.deepQuery( | |
[serie], 'tooltip' | |
)); | |
} | |
// 数据项 | |
formatter = self.deepQuery( | |
[data], 'tooltip.formatter' | |
) || formatter; | |
specialCssText += _style(self.deepQuery([data], 'tooltip')); | |
} | |
else { | |
formatter = self.deepQuery( | |
[data, serie, option], | |
'tooltip.islandFormatter' | |
); | |
} | |
if (typeof formatter == 'function') { | |
_curTicket = serie.name | |
+ ':' | |
+ ecData.get(_curTarget, 'dataIndex'); | |
_tDom.innerHTML = formatter( | |
[ | |
serie.name, | |
name, | |
value, | |
speical | |
], | |
_curTicket, | |
_setContent | |
); | |
} | |
else if (typeof formatter == 'string') { | |
formatter = formatter.replace('{a}','{a0}') | |
.replace('{b}','{b0}') | |
.replace('{c}','{c0}') | |
.replace('{d}','{d0}'); | |
formatter = formatter.replace('{a0}', serie.name) | |
.replace('{b0}', name) | |
.replace('{c0}', value); | |
if (typeof speical != 'undefined') { | |
formatter = formatter.replace('{d0}', speical); | |
} | |
_tDom.innerHTML = formatter; | |
} | |
else { | |
if (serie.type == ecConfig.CHART_TYPE_SCATTER) { | |
_tDom.innerHTML = serie.name + '<br/>' + | |
(name === '' ? '' : (name + ' : ')) | |
+ value + | |
(typeof speical == 'undefined' | |
? '' | |
: (' (' + speical + ')')); | |
} | |
else if (serie.type == ecConfig.CHART_TYPE_RADAR) { | |
indicator = speical; | |
html += (name === '' ? serie.name : name) + '<br />'; | |
for (var i = 0 ; i < indicator.length; i ++) { | |
html += indicator[i].text + ' : ' + value[i] + '<br />'; | |
} | |
_tDom.innerHTML = html; | |
} | |
else { | |
_tDom.innerHTML = serie.name + '<br/>' + | |
name + ' : ' + value + | |
(typeof speical == 'undefined' | |
? '' | |
: (' (' + speical + ')')); | |
} | |
} | |
if (!self.hasAppend) { | |
_tDom.style.left = _zrWidth / 2 + 'px'; | |
_tDom.style.top = _zrHeight / 2 + 'px'; | |
dom.firstChild.appendChild(_tDom); | |
self.hasAppend = true; | |
} | |
_show( | |
zrEvent.getX(_event) + 20, | |
zrEvent.getY(_event) - 20, | |
specialCssText | |
); | |
if (!_axisLineShape.invisible) { | |
_axisLineShape.invisible = true; | |
zr.modShape(_axisLineShape.id, _axisLineShape); | |
zr.refresh(); | |
} | |
} | |
/** | |
* 设置坐标轴指示器样式 | |
*/ | |
function _styleAxisPointer( | |
seriesArray, xStart, yStart, xEnd, yEnd, gap | |
) { | |
if (seriesArray.length > 0) { | |
var queryTarget; | |
var curType; | |
var axisPointer = option.tooltip.axisPointer; | |
var pointType = axisPointer.type; | |
var lineColor = axisPointer.lineStyle.color; | |
var lineWidth = axisPointer.lineStyle.width; | |
var lineType = axisPointer.lineStyle.type; | |
var areaSize = axisPointer.areaStyle.size; | |
var areaColor = axisPointer.areaStyle.color; | |
for (var i = 0, l = seriesArray.length; i < l; i++) { | |
if (self.deepQuery( | |
[seriesArray[i], option], 'tooltip.trigger' | |
) == 'axis' | |
) { | |
queryTarget = [seriesArray[i]]; | |
curType = self.deepQuery( | |
queryTarget, | |
'tooltip.axisPointer.type' | |
); | |
pointType = curType || pointType; | |
if (curType == 'line') { | |
lineColor = self.deepQuery( | |
queryTarget, | |
'tooltip.axisPointer.lineStyle.color' | |
) || lineColor; | |
lineWidth = self.deepQuery( | |
queryTarget, | |
'tooltip.axisPointer.lineStyle.width' | |
) || lineWidth; | |
lineType = self.deepQuery( | |
queryTarget, | |
'tooltip.axisPointer.lineStyle.type' | |
) || lineType; | |
} | |
else if (curType == 'shadow') { | |
areaSize = self.deepQuery( | |
queryTarget, | |
'tooltip.axisPointer.areaStyle.size' | |
) || areaSize; | |
areaColor = self.deepQuery( | |
queryTarget, | |
'tooltip.axisPointer.areaStyle.color' | |
) || areaColor; | |
} | |
} | |
} | |
if (pointType == 'line') { | |
_axisLineShape.style = { | |
xStart : xStart, | |
yStart : yStart, | |
xEnd : xEnd, | |
yEnd : yEnd, | |
strokeColor : lineColor, | |
lineWidth : lineWidth, | |
lineType : lineType | |
}; | |
_axisLineShape.invisible = false; | |
zr.modShape(_axisLineShape.id, _axisLineShape); | |
} | |
else if (pointType == 'shadow') { | |
if (typeof areaSize == 'undefined' | |
|| areaSize == 'auto' | |
|| isNaN(areaSize) | |
) { | |
lineWidth = gap; | |
} | |
else { | |
lineWidth = areaSize; | |
} | |
if (xStart == xEnd) { | |
// 纵向 | |
if (Math.abs(grid.getX() - xStart) < 2) { | |
// 最左边 | |
lineWidth /= 2; | |
xStart = xEnd = xEnd + lineWidth / 2; | |
} | |
else if (Math.abs(grid.getXend() - xStart) < 2) { | |
// 最右边 | |
lineWidth /= 2; | |
xStart = xEnd = xEnd - lineWidth / 2; | |
} | |
} | |
else if (yStart == yEnd) { | |
// 横向 | |
if (Math.abs(grid.getY() - yStart) < 2) { | |
// 最上边 | |
lineWidth /= 2; | |
yStart = yEnd = yEnd + lineWidth / 2; | |
} | |
else if (Math.abs(grid.getYend() - yStart) < 2) { | |
// 最右边 | |
lineWidth /= 2; | |
yStart = yEnd = yEnd - lineWidth / 2; | |
} | |
} | |
_axisShadowShape.style = { | |
xStart : xStart, | |
yStart : yStart, | |
xEnd : xEnd, | |
yEnd : yEnd, | |
strokeColor : areaColor, | |
lineWidth : lineWidth | |
}; | |
_axisShadowShape.invisible = false; | |
zr.modShape(_axisShadowShape.id, _axisShadowShape); | |
} | |
zr.refresh(); | |
} | |
} | |
/** | |
* zrender事件响应:鼠标移动 | |
*/ | |
function _onmousemove(param) { | |
clearTimeout(_hidingTicket); | |
clearTimeout(_showingTicket); | |
var target = param.target; | |
var mx = zrEvent.getX(param.event); | |
var my = zrEvent.getY(param.event); | |
if (!target) { | |
// 判断是否落到直角系里,axis触发的tooltip | |
_curTarget = false; | |
_event = param.event; | |
_event._target = _event.target || _event.toElement; | |
_event.zrenderX = mx; | |
_event.zrenderY = my; | |
if (_needAxisTrigger | |
&& grid | |
&& zrArea.isInside( | |
rectangle, | |
grid.getArea(), | |
mx, | |
my | |
) | |
) { | |
_showingTicket = setTimeout(_tryShow, _showDelay); | |
} | |
else if (_needAxisTrigger | |
&& polar | |
&& polar.isInside([mx, my]) != -1 | |
) { | |
_showingTicket = setTimeout(_tryShow, _showDelay); | |
} | |
else { | |
_hidingTicket = setTimeout(_hide, _hideDelay); | |
} | |
} | |
else { | |
_curTarget = target; | |
_event = param.event; | |
_event._target = _event.target || _event.toElement; | |
_event.zrenderX = mx; | |
_event.zrenderY = my; | |
var polarIndex; | |
if (_needAxisTrigger | |
&& polar | |
&& (polarIndex = polar.isInside([mx, my])) != -1 | |
) { | |
// 看用这个polar的系列数据是否是axis触发,如果是设置_curTarget为nul | |
var series = option.series; | |
for (var i = 0, l = series.length; i < l; i++) { | |
if (series[i].polarIndex == polarIndex | |
&& self.deepQuery( | |
[series[i], option], 'tooltip.trigger' | |
) == 'axis' | |
) { | |
_curTarget = null; | |
break; | |
} | |
} | |
} | |
_showingTicket = setTimeout(_tryShow, _showDelay); | |
} | |
} | |
/** | |
* zrender事件响应:鼠标离开绘图区域 | |
*/ | |
function _onglobalout() { | |
clearTimeout(_hidingTicket); | |
clearTimeout(_showingTicket); | |
_hidingTicket = setTimeout(_hide, _hideDelay); | |
} | |
/** | |
* 异步回调填充内容 | |
*/ | |
function _setContent(ticket, content) { | |
if (ticket == _curTicket) { | |
_tDom.innerHTML = content; | |
} | |
var cssText = ''; | |
var domHeight = _tDom.offsetHeight; | |
var domWidth = _tDom.offsetWidth; | |
if (_tDom.offsetLeft + domWidth > _zrWidth) { | |
cssText += 'left:' + (_zrWidth - domWidth) + 'px;'; | |
} | |
if (_tDom.offsetTop + domHeight > _zrHeight) { | |
cssText += 'top:' + (_zrHeight - domHeight) + 'px;'; | |
} | |
if (cssText !== '') { | |
_tDom.style.cssText += cssText; | |
} | |
if (_zrWidth - _tDom.offsetLeft < 100 | |
|| _zrHeight - _tDom.offsetTop < 100 | |
) { | |
// 太靠边的做一次refixed | |
setTimeout(_refixed, 20); | |
} | |
} | |
function setComponent(newComponent) { | |
component = newComponent; | |
grid = component.grid; | |
xAxis = component.xAxis; | |
yAxis = component.yAxis; | |
polar = component.polar; | |
} | |
function init(newOption, newDom) { | |
option = newOption; | |
dom = newDom; | |
option.tooltip = self.reformOption(option.tooltip); | |
option.tooltip.textStyle = zrUtil.merge( | |
option.tooltip.textStyle, | |
ecConfig.textStyle, | |
{ | |
'overwrite': false, | |
'recursive': true | |
} | |
); | |
// 补全padding属性 | |
option.tooltip.padding = self.reformCssArray( | |
option.tooltip.padding | |
); | |
_needAxisTrigger = false; | |
if (option.tooltip.trigger == 'axis') { | |
_needAxisTrigger = true; | |
} | |
var series = option.series; | |
for (var i = 0, l = series.length; i < l; i++) { | |
if (self.deepQuery([series[i]], 'tooltip.trigger') | |
== 'axis' | |
) { | |
_needAxisTrigger = true; | |
break; | |
} | |
} | |
_showDelay = option.tooltip.showDelay; | |
_hideDelay = option.tooltip.hideDelay; | |
_defaultCssText = _style(option.tooltip); | |
_tDom.style.position = 'absolute'; // 不是多余的,别删! | |
self.hasAppend = false; | |
} | |
/** | |
* 刷新 | |
*/ | |
function refresh(newOption) { | |
if (newOption) { | |
option = newOption; | |
option.tooltip = self.reformOption(option.tooltip); | |
option.tooltip.textStyle = zrUtil.merge( | |
option.tooltip.textStyle, | |
ecConfig.textStyle, | |
{ | |
'overwrite': false, | |
'recursive': true | |
} | |
); | |
// 补全padding属性 | |
option.tooltip.padding = self.reformCssArray( | |
option.tooltip.padding | |
); | |
} | |
} | |
/** | |
* zrender事件响应:窗口大小改变 | |
*/ | |
function resize() { | |
_zrHeight = zr.getHeight(); | |
_zrWidth = zr.getWidth(); | |
} | |
/** | |
* 释放后实例不可用,重载基类方法 | |
*/ | |
function dispose() { | |
clearTimeout(_hidingTicket); | |
clearTimeout(_showingTicket); | |
zr.un(zrConfig.EVENT.MOUSEMOVE, _onmousemove); | |
zr.un(zrConfig.EVENT.GLOBALOUT, _onglobalout); | |
if (self.hasAppend) { | |
dom.firstChild.removeChild(_tDom); | |
} | |
_tDom = null; | |
// self.clear(); | |
self.shapeList = null; | |
self = null; | |
} | |
zr.on(zrConfig.EVENT.MOUSEMOVE, _onmousemove); | |
zr.on(zrConfig.EVENT.GLOBALOUT, _onglobalout); | |
// 重载基类方法 | |
self.dispose = dispose; | |
self.init = init; | |
self.refresh = refresh; | |
self.resize = resize; | |
self.setComponent = setComponent; | |
init(option, dom); | |
} | |
require('../component').define('tooltip', Tooltip); | |
return Tooltip; | |
}); |