zoukankan      html  css  js  c++  java
  • echarts实现自动轮播tooltip

    最近需要实现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=" 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 
     75     function autoHover() {
     76         var zrender = myChart.getZrender();
     77         var elements = zrender.storage._elements;
     78         var times = 0;
     79         console.log(elements);
     80 
     81         for (var key in elements) {
     82             var style = elements[key].style;
     83 
     84             //根据series中的一系列name值对elements进行归类排序,然后在进行hover
     85             //过滤条件需要完善
     86             if (elements[key]._echartsData) {
     87                 console.log(style);
     88                 (function (style, times) {
     89                     setTimeout(function () {
     90                         zrender.trigger('mousemove', {
     91                             zrenderX: Math.ceil(style.x + style.width/2),
     92                             zrenderY: Math.ceil(style.y + style.height/2)
     93                         });
     94                     }, 1000 * times);
     95                 })(style, times);
     96 
     97                 times++;
     98                 times %= counts;
     99             }
    100         }
    101     }
    102 </script>
    103 </body>
    104 </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 +            if (isAxisTrigger) {
     2  +                // axis trigger 3  +                var dataIndex = params.dataIndex;
     4  +                switch (chart.type) {
     5  +                    case ecConfig.CHART_TYPE_LINE :
     6  +                    case ecConfig.CHART_TYPE_BAR :
     7  +                    case ecConfig.CHART_TYPE_K :
     8  +                        if (typeof xAxis == 'undefined' 
     9  +                            || typeof yAxis == 'undefined'
    10  +                            || serie.data.length <= dataIndex
    11  +                        ) {
    12  +                            return;
    13  +                        }
    14  +                        var xAxisIndex = serie.xAxisIndex || 0;
    15  +                        var yAxisIndex = serie.yAxisIndex || 0;
    16  +                        if (xAxis.getAxis(xAxisIndex).type 
    17  +                            == ecConfig.COMPONENT_TYPE_AXIS_CATEGORY
    18  +                        ) {
    19  +                            // 横轴是类目20  +                            _event = {
    21  +                                zrenderX : xAxis.getAxis(xAxisIndex).getCoordByIndex(dataIndex),
    22  +                                zrenderY : grid.getY() + (grid.getYend() - grid.getY()) / 4
    23  +                            };
    24  +                        }
    25  +                        else {
    26  +                            // 纵轴是类目27  +                            _event = {
    28  +                                zrenderX : grid.getX() + (grid.getXend() - grid.getX()) / 4,
    29  +                                zrenderY : yAxis.getAxis(yAxisIndex).getCoordByIndex(dataIndex)
    30  +                            };
    31  +                        }
    32  +                        _showAxisTrigger(
    33  +                            xAxisIndex, 
    34  +                            yAxisIndex,
    35  +                            dataIndex
    36  +                        );
    37  +                        break;
    38  +                    case ecConfig.CHART_TYPE_RADAR :
    39  +                        if (typeof polar == 'undefined' 
    40  +                            || serie.data[0].value.length <= dataIndex
    41  +                        ) {
    42  +                            return;
    43  +                        }
    44  +                        var polarIndex = serie.polarIndex || 0;
    45  +                        var vector = polar.getVector(polarIndex, dataIndex, 'max')
    46  +                        _event = {
    47  +                            zrenderX : vector[0],
    48  +                            zrenderY : vector[1]
    49  +                        };
    50  +                        _showPolarTrigger(
    51  +                            polarIndex, 
    52  +                            dataIndex
    53  +                        );
    54  +                        break;
    55  +                }
    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              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

    作者:不曾潇洒
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    使用golang访问kubebernetes
    使用 Rancher 管理现有 Kubernetes 集群
    Running powershell scripts during nuget package installation and removal
    How to Create, Use, and Debug .NET application Crash Dumps in 2019
    寻找写代码感觉(一)之使用 Spring Boot 快速搭建项目
    Selenium+Java之解决org.openqa.selenium.InvalidArgumentException: invalid argument报错问题
    Selenium环境搭建
    关于Xpath定位方法知道这些基本够用
    Web自动化之浏览器启动
    【翻译】编写代码注释的最佳实践
  • 原文地址:https://www.cnblogs.com/chengwb/p/5833454.html
Copyright © 2011-2022 走看看