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="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 
 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             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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM