最近需要实现echarts图形中hover效果轮播(即tooltip在各个数据点上轮流显示)的功能,以下就是我学习的一个过程,只是提供思路,具体场景需要自己修改。(仅针对echarts 2.2.7及以下版本,最后的代码有3.0以上的使用方法以及插件代码链接)

源码:https://github.com/chengwubin/echarts-tooltip-auto-show

关于echarts大家可以查看官网文档

文档中有这么一段话:

自2.1.8起,我们为echarts开发了专门的合并压缩工具echarts-optimizer。如你所发现的,build文件夹下已经包含了由echarts-optimizer生成的单文件:

  • dist(文件夹) : 经过合并、压缩的单文件
    • echarts.js : 这是包含AMD加载器的echarts主文件,需要通过script最先引入
    • chart(文件夹) : echarts-optimizer通过依赖关系分析同时去除与echarts.js的重复模块后为echarts的每一个图表类型单独打包生成一个独立文件,根据应用需求可实现图表类型按需加载
      • line.js : 折线图(如需折柱动态类型切换,require时还需要echarts/chart/bar)
      • bar.js : 柱形图(如需折柱动态类型切换,require时还需要echarts/chart/line)
      • scatter.js : 散点图
      • k.js : K线图
      • pie.js : 饼图(如需饼漏斗图动态类型切换,require时还需要echarts/chart/funnel)
      • radar.js : 雷达图
      • map.js : 地图
      • force.js : 力导向布局图(如需力导和弦动态类型切换,require时还需要echarts/chart/chord)
      • chord.js : 和弦图(如需力导和弦动态类型切换,require时还需要echarts/chart/force)
      • funnel.js : 漏斗图(如需饼漏斗图动态类型切换,require时还需要echarts/chart/pie)
      • gauge.js : 仪表盘
      • eventRiver.js : 事件河流图
      • treemap.js : 矩阵树图
      • venn.js : 韦恩图
  • source(文件夹) : 经过合并,但并没有压缩的单文件,内容同dist,可用于调试

要的就是source文件下面的文件,可以调试,把source下面的echarts-all.js导入自己的工程,在找一个例子就可以运行看效果了。

  1. <div id="chart" style="width: 800px; height: 500px;">
  2. </div>
  3. <span id="hover-console"></span>
  4. <span id="console"></span>
  5.  
  6. <script src="./js/echarts-all.js"></script>
  7. <script type="text/javascript">
  8. // 基于准备好的dom,初始化echarts图表
  9. var myChart = echarts.init(document.getElementById('chart'));
  10. console.log(myChart);
  11. var option = {
  12. tooltip: {
  13. show: true
  14. },
  15. legend: {
  16. data:['销量']
  17. },
  18. xAxis : [
  19. {
  20. type : 'category',
  21. data : ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
  22. }
  23. ],
  24. yAxis : [
  25. {
  26. type : 'value'
  27. }
  28. ],
  29. series : [
  30. {
  31. "name":"销量",
  32. "type":"bar",
  33. "data":[5, 20, 40, 10, 10, 20]
  34. }
  35. ]
  36. };
  37.  
  38. // 为echarts对象加载数据
  39. myChart.setOption(option);
  40.  
  41. var ecConfig = echarts.config;
  42. function eConsole(param) {
  43. var mes = '【' + param.type + '】';
  44. if (typeof param.seriesIndex != 'undefined') {
  45. mes += ' seriesIndex : ' + param.seriesIndex;
  46. mes += ' dataIndex : ' + param.dataIndex;
  47. }
  48. if (param.type == 'hover') {
  49. document.getElementById('hover-console').innerHTML = 'Event Console : ' + mes;
  50. }
  51. else {
  52. document.getElementById('console').innerHTML = mes;
  53. }
  54. }
  55.  
  56. function eHover(param) {
  57. var mes = '【' + param.type + '】';
  58. if (typeof param.seriesIndex != 'undefined') {
  59. mes += ' seriesIndex : ' + param.seriesIndex;
  60. mes += ' dataIndex : ' + param.dataIndex;
  61. }
  62. document.getElementById('hover-console').innerHTML = 'Event Console : ' + mes;
  63. }
  64. myChart.on(ecConfig.EVENT.HOVER, eHover);
  65. </script>

先说一下大概思路,由于是canvas上面绘图,所以界面上没有对应的dom元素,所以没法用js中的事件来控制。

我们要触发事件,就需要先得到图上面的数据元素,然后再考虑怎么触发事件。 

稍微看一下源码,就发现里面经常出现zrender,所以要先弄清楚zrender做什么的,查看zrender资料

看了zrender的介绍,大概知道是用来处理canvas的绘画的,同时还封装了dom的事件(模拟)。

了解了zrender之后还是继续调试看源码,echarts-all.js文件太大,不太方便,可以下载zrender的源码查看对应的代码文件。

最开始我是想从例子中的hover事件入手,进行调试查看,最后查看到实际是mousemove事件触发的,然后发现zrender中有个storage。

查看了一下storage:

  1. /**
  2. * 内容仓库 (M)
  3. * @alias module:zrender/Storage
  4. * @constructor
  5. */
  6. var Storage = function () {
  7. // 所有常规形状,id索引的map
  8. this._elements = {};
  9.  
  10. this._roots = [];
  11.  
  12. this._displayList = [];
  13.  
  14. this._displayListLen = 0;
  15. };

是不是发现了新大陆!!!_elements,对,我们要的就是它。

但是怎么得到呢,后面在echarts中找到了getZrender(),添加代码:

  1. var zrender = myChart.getZrender();
  2. var elements = zrender.storage._elements;
  3. console.log(elements);

运行后可以在console中看见elements的内容:

确实是我们想要的。

然后就是要处理触发事件了,怎么在指定坐标触发事件呢?网上查了查没查到相关信息,很多网友说的是不能再指定坐标触发事件,当时我就懵逼了!!!

但是想想,zrender里面封装了事件的,可以看看怎么从这里入手,是的,最后找到了解决办法:

  1. zrender.trigger('mousemove', {
  2. zrenderX: style.x,
  3. zrenderY: style.y
  4. });

试了下,成功了!!!!!!

说的比较粗糙,此文仅供参考,如过您有更好的方法希望能够分享出来,大家一起学习,哈哈!

下面贴上完整代码:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <style>
  7. .chart {
  8. height: 500px;
  9. width: 800px;
  10. }
  11. </style>
  12. </head>
  13. <body>
  14. <div id="chart" class="chart">
  15.  
  16. </div>
  17. <span id="hover-console"></span>
  18. <span id="console"></span>
  19.  
  20. <script src="./js/echarts-all.js"></script>
  21. <script type="text/javascript">
  22. // 基于准备好的dom,初始化echarts图表
  23. var myChart = echarts.init(document.getElementById('chart'));
  24. console.log(myChart);
  25. var option = {
  26. tooltip: {
  27. show: true
  28. },
  29. legend: {
  30. data:['销量']
  31. },
  32. xAxis : [
  33. {
  34. type : 'category',
  35. data : ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
  36. }
  37. ],
  38. yAxis : [
  39. {
  40. type : 'value'
  41. }
  42. ],
  43. series : [
  44. {
  45. "name":"销量",
  46. "type":"bar",
  47. "data":[5, 20, 40, 10, 10, 20]
  48. }
  49. ]
  50. };
  51.  
  52. // 为echarts对象加载数据
  53. myChart.setOption(option);
  54.  
  55. var ecConfig = echarts.config;
  56. function eHover(param) {
  57. var mes = '【' + param.type + '】';
  58. if (typeof param.seriesIndex != 'undefined') {
  59. mes += ' seriesIndex : ' + param.seriesIndex;
  60. mes += ' dataIndex : ' + param.dataIndex;
  61. }
  62. document.getElementById('hover-console').innerHTML = 'Event Console : ' + mes;
  63. }
  64. myChart.on(ecConfig.EVENT.HOVER, eHover);
  65.  
  66. //可以获取有效的数据元素,数据元素属性包含坐标点和长宽(如果页面有变化需要重新获取)
  67. var counts = option.series[0].data.length;
  68.  
  69. setTimeout(function() {
  70. autoHover();
  71. setInterval(autoHover, 1000 * counts);
  72. }, 1000);
  73.  
  74. function autoHover() {
  75. var zrender = myChart.getZrender();
  76. var elements = zrender.storage._elements;
  77. var times = 0;
  78. console.log(elements);
  79.  
  80. for (var key in elements) {
  81. var style = elements[key].style;
  82.  
  83. //根据series中的一系列name值对elements进行归类排序,然后在进行hover
  84. //过滤条件需要完善
  85. if (elements[key]._echartsData) {
  86. console.log(style);
  87. (function (style, times) {
  88. setTimeout(function () {
  89. zrender.trigger('mousemove', {
  90. zrenderX: Math.ceil(style.x + style.width/2),
  91. zrenderY: Math.ceil(style.y + style.height/2)
  92. });
  93. }, 1000 * times);
  94. })(style, times);
  95.  
  96. times++;
  97. times %= counts;
  98. }
  99. }
  100. }
  101. </script>
  102. </body>
  103. </html>

当鼠标触发hover时要取消自动效果,这个就大家自己解决了!哈哈

第一次发文,见笑了!

PS:这个问题发现上面的处理不合适哈,echarts中提供了tooltip显示的方法,一直没更新,今天得空更新下。

为了解决有鼠标触发hover时怎么控制轮播效果的停止和开始,更细的去查看echarts和zrender的事件,看来看去感觉外部处理很困难,最后思路还是回到了tooltip上。
最后发现tooltip中其实是有提供showTip和hideTip方法,然后看echarts文档上component中的tooltip也有写这两个方法,然后添加代码:

  1. var tooltip = myChart.component.tooltip;
  2. //showTip方法参数请参见echarts文档
  3. tooltip.showTip({seriesIndex: '1', dataIndex: '1'});

运行发现根本没效果(bar类型)。。。。。。。。。。。。。调试发现tooltip中showTip()源码:

  1. if (isAxisTrigger) {
  2. var dataIndex = params.dataIndex;
  3. switch (chart.type) {
  4. case ecConfig.CHART_TYPE_LINE:
  5. case ecConfig.CHART_TYPE_BAR:
  6. case ecConfig.CHART_TYPE_K:
  7. case ecConfig.CHART_TYPE_RADAR:
  8.     //问题就在这儿,serie.data[0].value是什么鬼?
  9. if (this.component.polar == null || serie.data[0].value.length <= dataIndex) {
  10. return;
  11. }
  12. var polarIndex = serie.polarIndex || 0;
  13. var vector = this.component.polar.getVector(polarIndex, dataIndex, 'max');
  14. this._event = {
  15.   zrenderX: vector[0],
  16.   zrenderY: vector[1]
  17. };
  18. this._showPolarTrigger(polarIndex, dataIndex);
  19.   break;
  20. }
  21. }

然后在github上查看以前的版本,发现早在echarts 1.4版本中就加入了showTip()hideTip()的功能了,提交链接。
可以看见showTip():

  1. 1 + if (isAxisTrigger) {
  2. 2 + // axis trigger 3 + var dataIndex = params.dataIndex;
  3. 4 + switch (chart.type) {
  4. 5 + case ecConfig.CHART_TYPE_LINE :
  5. 6 + case ecConfig.CHART_TYPE_BAR :
  6. 7 + case ecConfig.CHART_TYPE_K :
  7. 8 + if (typeof xAxis == 'undefined'
  8. 9 + || typeof yAxis == 'undefined'
  9. 10 + || serie.data.length <= dataIndex
  10. 11 + ) {
  11. 12 + return;
  12. 13 + }
  13. 14 + var xAxisIndex = serie.xAxisIndex || 0;
  14. 15 + var yAxisIndex = serie.yAxisIndex || 0;
  15. 16 + if (xAxis.getAxis(xAxisIndex).type
  16. 17 + == ecConfig.COMPONENT_TYPE_AXIS_CATEGORY
  17. 18 + ) {
  18. 19 + // 横轴是类目20 + _event = {
  19. 21 + zrenderX : xAxis.getAxis(xAxisIndex).getCoordByIndex(dataIndex),
  20. 22 + zrenderY : grid.getY() + (grid.getYend() - grid.getY()) / 4
  21. 23 + };
  22. 24 + }
  23. 25 + else {
  24. 26 + // 纵轴是类目27 + _event = {
  25. 28 + zrenderX : grid.getX() + (grid.getXend() - grid.getX()) / 4,
  26. 29 + zrenderY : yAxis.getAxis(yAxisIndex).getCoordByIndex(dataIndex)
  27. 30 + };
  28. 31 + }
  29. 32 + _showAxisTrigger(
  30. 33 + xAxisIndex,
  31. 34 + yAxisIndex,
  32. 35 + dataIndex
  33. 36 + );
  34. 37 + break;
  35. 38 + case ecConfig.CHART_TYPE_RADAR :
  36. 39 + if (typeof polar == 'undefined'
  37. 40 + || serie.data[0].value.length <= dataIndex
  38. 41 + ) {
  39. 42 + return;
  40. 43 + }
  41. 44 + var polarIndex = serie.polarIndex || 0;
  42. 45 + var vector = polar.getVector(polarIndex, dataIndex, 'max')
  43. 46 + _event = {
  44. 47 + zrenderX : vector[0],
  45. 48 + zrenderY : vector[1]
  46. 49 + };
  47. 50 + _showPolarTrigger(
  48. 51 + polarIndex,
  49. 52 + dataIndex
  50. 53 + );
  51. 54 + break;
  52. 55 + }
  53. 56 + }

我顺便找了一下是在2.2.2-到2.2.3版本中被改了。

下面这段代码被改过了:

  1. switch (chart.type) {
  2. case ecConfig.CHART_TYPE_LINE :
  3. case ecConfig.CHART_TYPE_BAR :
  4. case ecConfig.CHART_TYPE_K :
  5. //应该只是想删掉这个项,结果把处理程序也删了
  6. //case ecConfig.CHART_TYPE_TREEMAP :
  7. if (this.component.xAxis == null
  8. || this.component.yAxis == null
  9. || serie.data.length <= dataIndex
  10. ) {
  11. return;
  12. }
  13. var xAxisIndex = serie.xAxisIndex || 0;
  14. var yAxisIndex = serie.yAxisIndex || 0;
  15. if (this.component.xAxis.getAxis(xAxisIndex).type
  16. === ecConfig.COMPONENT_TYPE_AXIS_CATEGORY
  17. ) {
  18. // 横轴是类目
  19. this._event = {
  20. zrenderX: this.component.xAxis.getAxis(xAxisIndex)
  21. .getCoordByIndex(dataIndex),
  22. zrenderY: this.component.grid.getY()
  23. + (this.component.grid.getYend()
  24. - this.component.grid.getY()
  25. ) / 4
  26. };
  27. }
  28. else {
  29. // 纵轴是类目
  30. this._event = {
  31. zrenderX: this.component.grid.getX()
  32. + (this.component.grid.getXend()
  33. - this.component.grid.getX()
  34. ) / 4,
  35. zrenderY: this.component.yAxis.getAxis(yAxisIndex)
  36. .getCoordByIndex(dataIndex)
  37. };
  38. }
  39. this._showAxisTrigger(
  40. xAxisIndex,
  41. yAxisIndex,
  42. dataIndex
  43. );
  44. break;

OK,把这个段删除的代码复制到你引用的echarts源码tooltip.js中,然后要合并的就重新合并压缩吧。

贴上例子:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <style>
  7. .chart {
  8. height: 500px;
  9. width: 800px;
  10. }
  11. </style>
  12. </head>
  13. <body>
  14. <div id="chart" class="chart">
  15.  
  16. </div>
  17. <span id="hover-console"></span>
  18. <span id="console"></span>
  19.  
  20. <script src="./js/jquery.js"></script>
  21. <script src="./js/echarts-all.js"></script>
  22. <script type="text/javascript">
  23. // 基于准备好的dom,初始化echarts图表
  24. var myChart = echarts.init(document.getElementById('chart'));
  25.  
  26. var option = {
  27. tooltip: {
  28. show: true29
  29. },
  30. legend: {
  31. data: ['销量']
  32. },
  33. xAxis: [
  34. {
  35. type: 'category',
  36. data: ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"]
  37. }
  38. ],
  39. yAxis: [
  40. {
  41. type: 'value'
  42. }
  43. ],
  44. series: [
  45. {
  46. "name": "销量",
  47. "type": "bar",
  48. "data": [5, 20, 40, 10, 10, 20]
  49. }
  50. ]
  51. };
  52.  
  53. // 为echarts对象加载数据
  54. myChart.setOption(option);
  55. var timer = 0;
  56.  
  57. var total = option.xAxis[0].data.length;
  58. var count = 0;
  59. var tooltip = myChart.component.tooltip;
  60. function autoTip() {
  61. timer = setInterval(function () {
  62. var curr = count % total;
  63.  
  64. //3.0以上版本的showTip使用方式
  65. //myChart.dispatchAction({type: 'showTip', seriesIndex: '1', dataIndex: '1'});
  66. tooltip.showTip({seriesIndex: '0', dataIndex: curr});
  67. count += 1;
  68. }, 1000);
  69. }
  70. autoTip();
  71.  
  72. var zRender = myChart.getZrender();
  73. //mousemove和mouseout总是成对出现,而且out先出现。。。。所以没法解决鼠标hover时暂停自动tip的效果
  74. zRender.on('mousemove', function (param) {
  75. console.log('move')
  76. if (timer) {
  77. clearInterval(timer);
  78. timer = 0;
  79. }
  80. });
  81. zRender.on('mouseout', function (param) {
  82. console.log('OUT');
  83. if (param.event) {
  84. //判断坐标是否在图表上,然后在处理应该可以实现
  85. if (!timer) {
  86. autoTip();
  87. }
  88. }
  89. });
  90. </script>
  91. </body>
  92. </html>

补充:

3.0以上的实现方法已经在github共享了代码,可以直接下载使用,如有问题欢迎补充纠正:

https://github.com/chengwubin/echarts-tooltip-auto-show

echarts实现自动轮播tooltip的更多相关文章

  1. [个人项目] echarts 实现数据(tooltip)自动轮播插件

    前言 最近, 工作中要做类似这种的项目. 用到了百度的 echarts 这个开源的数据可视化的框架. 因为投屏项目不像PC端的WEB, 它不允许用户用鼠标键盘等交互. 有些图表只能看到各部分的占比情况 ...

  2. 使用ViewPager实现自动轮播

    很多APP中都实现了类似引导页的自动轮播,不由得想到昨天的引导页上修改一下代码实现轮播. 其实大体上只需要添加一个线程循环执行就可以了. 项目已同步至:https://github.com/nanch ...

  3. ViewPager自动轮播

    Android使用ViewPager实现左右循环滑动及轮播效果   ViewPager是一个常用的android组件,不过通常我们使用ViewPager的时候不能实现左右无限循环滑动,在滑到边界的时候 ...

  4. jQuery实现选项联动轮播

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. 仿网易新闻 ViewPager 实现图片自动轮播

    新闻 App 首页最上方一般会循环播放热点图片,如下图所示. 本文主要介绍了利用 ViewPager 实现轮播图片,图片下方加上小圆点指示器标记当前位置,并利用 Timer+Handler 实现了自动 ...

  6. ios - 图片自动轮播定时器(NSTimer)以及消息循环模式简介

    本文只是演示如何设置图片轮播的定时器. 创建全局变量NSTimer 程序启动后就开始轮播图片,所以在- (void)viewDidLoad中就启动定时器. 将定时器放入消息循环池中.- (void)v ...

  7. Jquery+css实现图片无缝滚动轮播

    Today,在XX学院的教学视频中,偶尔看到了Jquery+css实现图片无缝滚动轮播视频教程,虽然以前已写过类似的,但是我感觉他学的比较精简.为了方便以后做项目时直接拷贝,特地写出来,顺便和大家分享 ...

  8. 讲解版的自动轮播(新手福利)样式和js就不分离了为了看的方便

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  9. javascript焦点图左右按钮简单自动轮播

    这里把css和html合在一块写了,这块代码只是布局和样式不是重点 <!DOCTYPE html> <html> <head> <meta charset=& ...

随机推荐

  1. c# in out ref关键字

    class in_out_ref { #region in 关键字 delegate void DContravariant<in A>(A argumen); static void o ...

  2. HBase原理–所有Region切分的细节都在这里了

    本文由  网易云发布.   作者:范欣欣(本篇文章仅限内部分享,如需转载,请联系网易获取授权.)   Region自动切分是HBase能够拥有良好扩张性的最重要因素之一,也必然是所有分布式系统追求无限 ...

  3. 【ocp-12c】最新Oracle OCP-071考试题库(41题)

    41.(8-14) choose two View the Exhibit and examine the structure of the ORDERS table. The columns ORD ...

  4. 几种封装javaBean的方法

    开发框架时,经常需要使用java对象(javaBean)的属性来封装程序的数据,封装javaBean的方法有很多,比如反射,内省,以及使用工具类.下面从反射开始介绍. 1.javaBean介绍: 简介 ...

  5. Ubuntu下增加eclipse菜单图标并配置java path(解决点击图标不能启动eclipse的问题)

    Ubuntu下增加eclipse菜单图标 Ubuntu的菜单图标在/usr/share/applications目录下. 1. 在/usr/share/applications目录下新建eclipse ...

  6. Optional类

    参照: 一篇简单使用介绍 官网详细用法介绍 包含各种例子的cheetsheet 一个封装某个value的容器 一般可用于方法返回值类型,提醒调用方,这个值可能为null,所以需要处理(因为空指针异常是 ...

  7. 无比迅速敏捷地开发iOS超精美控件

    目录 前言 设计 编码 PaintCode 前言 自从人生第一篇博客<iOS中的预编译指令的初步探究>问世以来 浏览量竟然达到了360多,(路过的大神勿笑!)这些浏览量使我兴奋异常但又令我 ...

  8. Safari 不能播放Video ,Chrome等可以 问题解决。

    1  原因分析 https://www.zhihu.com/question/41818719 2 代码实现 1 注意点: 请求时 : header中 range 请求多少长度 代码要返回相应的长度  ...

  9. 配置不同站点不同版本PHP

    Apache 配置 1.常规手动部署apache方法(不会apache配置的请先移步看下Apache基本手工配置方法),解压fcgid,取其mod_fcgid.so至modules目录 2.打开htt ...

  10. [转] ELK 之 Logstash

    [From] https://blog.csdn.net/iguyue/article/details/77006201 ELK 之 Logstash 简介: ELK 之 LogstashLogsta ...