课程表

Echarts 基础教程

Echarts 案例教程

工具箱
速查手册

Echarts 实现拖拽

当前位置:免费教程 » JS/JS库/框架 » Echarts

介绍一个实现拖拽的小例子。这个例子是在原生 echarts 基础上做了些小小扩展,带有一定的交互性。通过这个例子,我们可以了解到,如何使用 echarts 提供的 API 实现定制化的富交互的功能。

在线运行案例>>>

这个例子主要做到了这样一件事,用鼠标可以拖拽曲线的点,从而改变曲线的形状。例子很简单,但是有了这个基础我们还可以做更多的事情,比如在图中可视化得编辑。所以我们从这个简单的例子开始。

echarts 本身没有提供封装好的『拖拽改变图表』功能,因为现在认为这个功能并不足够有通用性。那么这个功能就留给开发者用 API 实现,这也有助于开发者按自己的需要个性定制。

(一)实现基本的拖拽功能

在这个例子中,基础的图表是一个 折线图 (series-line)。参见如下配置:

  1. var symbolSize = 20;
  2.  
  3. // 这个 data 变量在这里单独声明,在后面也会用到。
  4. var data = [[15, 0], [-50, 10], [-56.5, 20], [-46.5, 30], [-22.1, 40]];
  5.  
  6. myChart.setOption({
  7.     xAxis: {
  8.         min: -100,
  9.         max: 80,
  10.         type: 'value',
  11.         axisLine: {onZero: false}
  12.     },
  13.     yAxis: {
  14.         min: -30,
  15.         max: 60,
  16.         type: 'value',
  17.         axisLine: {onZero: false}
  18.     },
  19.     series: [
  20.         {
  21.             id: 'a',
  22.             type: 'line',
  23.             smooth: true,
  24.             symbolSize: symbolSize, // 为了方便拖拽,把 symbolSize 尺寸设大了。
  25.             data: data
  26.         }
  27.     ]
  28. });

既然折线中原生的点没有拖拽功能,我们就为它加上拖拽功能:用 graphic 组件,在每个点上面,覆盖一个隐藏的可拖拽的圆点。

  1. myChart.setOption({
  2.     // 声明一个 graphic component,里面有若干个 type 为 'circle' 的 graphic elements。
  3.     // 这里使用了 echarts.util.map 这个帮助方法,其行为和 Array.prototype.map 一样,但是兼容 es5 以下的环境。
  4.     // 用 map 方法遍历 data 的每项,为每项生成一个圆点。
  5.     graphic: echarts.util.map(data, function (dataItem, dataIndex) {
  6.         return {
  7.             // 'circle' 表示这个 graphic element 的类型是圆点。
  8.             type: 'circle',
  9.  
  10.             shape: {
  11.                 // 圆点的半径。
  12.                 r: symbolSize / 2
  13.             },
  14.             // 用 transform 的方式对圆点进行定位。position: [x, y] 表示将圆点平移到 [x, y] 位置。
  15.             // 这里使用了 convertToPixel 这个 API 来得到每个圆点的位置,下面介绍。
  16.             position: myChart.convertToPixel('grid', dataItem),
  17.  
  18.             // 这个属性让圆点不可见(但是不影响他响应鼠标事件)。
  19.             invisible: true,
  20.             // 这个属性让圆点可以被拖拽。
  21.             draggable: true,
  22.             // 把 z 值设得比较大,表示这个圆点在最上方,能覆盖住已有的折线图的圆点。
  23.             z: 100,
  24.             // 此圆点的拖拽的响应事件,在拖拽过程中会不断被触发。下面介绍详情。
  25.             // 这里使用了 echarts.util.curry 这个帮助方法,意思是生成一个与 onPointDragging
  26.             // 功能一样的新的函数,只不过第一个参数永远为此时传入的 dataIndex 的值。
  27.             ondrag: echarts.util.curry(onPointDragging, dataIndex)
  28.         };
  29.     })
  30. });

上面的代码中,使用 convertToPixel 这个 API,进行了从 data 到『像素坐标』的转换,从而得到了每个圆点应该在的位置,从而能绘制这些圆点。myChart.convertToPixel('grid', dataItem) 这句话中,第一个参数 'grid' 表示 dataItem 在 grid 这个组件中(即直角坐标系)中进行转换。所谓『像素坐标』,就是以 echarts 容器 dom element 的左上角为零点的以像素为单位的坐标系中的坐标。

注意这件事需要在第一次 setOption 后再进行,也就是说,须在坐标系(grid)初始化后才能调用 myChart.convertToPixel('grid', dataItem)。

有了这段代码后,就有了诸个能拖拽的点。接下来要为每个点,加上拖拽响应的事件:

  1. // 拖拽某个圆点的过程中会不断调用此函数。
  2. // 此函数中会根据拖拽后的新位置,改变 data 中的值,并用新的 data 值,重绘折线图,从而使折线图同步于被拖拽的隐藏圆点。
  3. function onPointDragging(dataIndex) {
  4.     // 这里的 data 就是本文最初的代码块中声明的 data,在这里会被更新。
  5.     // 这里的 this 就是被拖拽的圆点。this.position 就是圆点当前的位置。
  6.     data[dataIndex] = myChart.convertFromPixel('grid', this.position);
  7.     // 用更新后的 data,重绘折线图。
  8.     myChart.setOption({
  9.         series: [{
  10.             id: 'a',
  11.             data: data
  12.         }]
  13.     });
  14. }

上面的代码中,使用了 convertFromPixel 这个 API。它是 convertToPixel 的逆向过程。myChart.convertFromPixel('grid', this.position) 表示把当前像素坐标转换成 grid 组件中直角坐标系的 dataItem 值。

最后,为了使 dom 尺寸改变时,图中的元素能自适应得变化,加上这些代码:

  1. window.addEventListener('resize', function () {
  2.     // 对每个拖拽圆点重新计算位置,并用 setOption 更新。
  3.     myChart.setOption({
  4.         graphic: echarts.util.map(data, function (item, dataIndex) {
  5.             return {
  6.                 position: myChart.convertToPixel('grid', item)
  7.             };
  8.         })
  9.     });
  10. });

(二)添加 tooltip 组件

到此,拖拽的基本功能就完成了。但是想要更进一步得实时看到拖拽过程中,被拖拽的点的 data 值的变化状况,我们可以使用 tooltip 组件来实时显示这个值。但是,tooltip 有其默认的『显示』『隐藏』触发规则,在我们拖拽的场景中并不适用,所以我们还要手动定制 tooltip 的『显示』『隐藏』行为。

在上述代码中分别添加如下定义:

  1. myChart.setOption({
  2.     ...,
  3.     tooltip: {
  4.         // 表示不使用默认的『显示』『隐藏』触发规则。
  5.         triggerOn: 'none',
  6.         formatter: function (params) {
  7.             return 'X: ' + params.data[0].toFixed(2) + '<br>Y: ' + params.data[1].toFixed(2);
  8.         }
  9.     }
  10. });
  11. myChart.setOption({
  12.     graphic: echarts.util.map(data, function (item, dataIndex) {
  13.         return {
  14.             type: 'circle',
  15.             ...,
  16.             // 在 mouseover 的时候显示,在 mouseout 的时候隐藏。
  17.             onmousemove: echarts.util.curry(showTooltip, dataIndex),
  18.             onmouseout: echarts.util.curry(hideTooltip, dataIndex),
  19.         };
  20.     })
  21. });
  22.  
  23. function showTooltip(dataIndex) {
  24.     myChart.dispatchAction({
  25.         type: 'showTip',
  26.         seriesIndex: 0,
  27.         dataIndex: dataIndex
  28.     });
  29. }
  30.  
  31. function hideTooltip(dataIndex) {
  32.     myChart.dispatchAction({
  33.         type: 'hideTip'
  34.     });
  35. }

这里使用了 dispatchAction 来显示隐藏 tooltip。用到了 showTip、hideTip。


(三)全部代码

总结一下,全部的代码如下:

  1. <!DOCTYPE html><html><head>
  2.     <meta charset="utf-8">
  3.     <script src="dist/echarts.min.js"></script></head><body>
  4.     <div id="main" style="width: 600px;height:400px;"></div>
  5.     <script type="text/javascript">
  6.  
  7.     var symbolSize = 20;
  8.     var data = [[15, 0], [-50, 10], [-56.5, 20], [-46.5, 30], [-22.1, 40]];
  9.  
  10.     var myChart = echarts.init(document.getElementById('main'));
  11.  
  12.     myChart.setOption({
  13.         tooltip: {
  14.             triggerOn: 'none',
  15.             formatter: function (params) {
  16.                 return 'X: ' + params.data[0].toFixed(2) + '<br>Y: ' + params.data[1].toFixed(2);
  17.             }
  18.         },
  19.         xAxis: {
  20.             min: -100,
  21.             max: 80,
  22.             type: 'value',
  23.             axisLine: {onZero: false}
  24.         },
  25.         yAxis: {
  26.             min: -30,
  27.             max: 60,
  28.             type: 'value',
  29.             axisLine: {onZero: false}
  30.         },
  31.         series: [
  32.             {
  33.                 id: 'a',
  34.                 type: 'line',
  35.                 smooth: true,
  36.                 symbolSize: symbolSize,
  37.                 data: data
  38.             }
  39.         ],
  40.     });
  41.  
  42.     myChart.setOption({
  43.         graphic: echarts.util.map(data, function (item, dataIndex) {
  44.             return {
  45.                 type: 'circle',
  46.                 position: myChart.convertToPixel('grid', item),
  47.                 shape: {
  48.                     r: symbolSize / 2
  49.                 },
  50.                 invisible: true,
  51.                 draggable: true,
  52.                 ondrag: echarts.util.curry(onPointDragging, dataIndex),
  53.                 onmousemove: echarts.util.curry(showTooltip, dataIndex),
  54.                 onmouseout: echarts.util.curry(hideTooltip, dataIndex),
  55.                 z: 100
  56.             };
  57.         })
  58.     });
  59.  
  60.     window.addEventListener('resize', function () {
  61.         myChart.setOption({
  62.             graphic: echarts.util.map(data, function (item, dataIndex) {
  63.                 return {
  64.                     position: myChart.convertToPixel('grid', item)
  65.                 };
  66.             })
  67.         });
  68.     });
  69.     
  70.     function showTooltip(dataIndex) {
  71.         myChart.dispatchAction({
  72.             type: 'showTip',
  73.             seriesIndex: 0,
  74.             dataIndex: dataIndex
  75.         });
  76.     }
  77.  
  78.     function hideTooltip(dataIndex) {
  79.         myChart.dispatchAction({
  80.             type: 'hideTip'
  81.         });
  82.     }
  83.  
  84.     function onPointDragging(dataIndex, dx, dy) {
  85.         data[dataIndex] = myChart.convertFromPixel('grid', this.position);
  86.         myChart.setOption({
  87.             series: [{
  88.                 id: 'a',
  89.                 data: data
  90.             }]
  91.         });
  92.     }
  93.  
  94. </script>
  95. </body>
  96. </html>

在线运行案例

有了这些基础,就可以定制更多的功能了。可以加 dataZoom 组件,可以制作一个直角坐标系上的绘图板等等。可以发挥想象力。

转载本站内容时,请务必注明来自W3xue,违者必究。
 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号