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

    作者:不曾潇洒
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    关键词提取算法TextRank
    我的博文目录整理
    Windows Azure一些小技巧集合
    js数组和树互转
    this.props.form.validateFields回调不执行问题
    d3的4.x与3.x版本的区别
    d3提示框,虚线,选择区域
    d3布局
    d3文件导入和导出
    d3交互
  • 原文地址:https://www.cnblogs.com/chengwb/p/5833454.html
Copyright © 2011-2022 走看看