今天给大家介绍 echarts 中一个小例子『拖拽改变图表』的实现。这个例子是在原生 echarts 基础上做了些小小扩展,带有一定的交互性。通过这个例子,我们可以了解到,如何使用 echarts 提供的 API 实现『定制化的』『富有交互的』功能。
URL:http://echarts.baidu.com/demo.html#line-draggable
这个例子主要做到了这样一件事,用鼠标可以拖拽曲线的点,从而改变曲线的形状。例子很简单,但是有了这个基础我们还可以发挥想象做更多的事情(例如在图中可视化得编辑)。所以一切从这个简单的例子开始。
echarts 本身没有提供封装好的『拖拽改变图表』功能,因为认为这个功能并不足够有通用性。那么它就留给开发者用 API 实现,这也有助于开发者按自己的需要个性定制。
【一】
在这个例子中,基础的图表是一个折线图(line chart)。参见如下配置:
既然折线中原生的点没有拖拽功能,我们就为它加上拖拽功能:用 graphic 组件,在每个点上面,覆盖一个隐藏的可拖拽的圆点。
上面的代码中,使用 convertToPixel 这个 API,进行了从 data 到『像素坐标』的转换,从而得到了每个圆点应该在的位置,从而能绘制这些圆点。myChart.convertToPixel('grid', dataItem) 这句话中,第一个参数 'grid' 表示 dataItem 在 grid 这个组件中(即直角坐标系)中进行转换。所谓『像素坐标』,就是以 echarts 容器 dom element 的左上角为零点的以像素为单位的坐标系中的坐标。
注意这件事需要在第一次 setOption 后再进行,也就是 grid 初始化后才能调用 myChart.convertToPixel('grid', dataItem)。
有了这段代码后,就有了诸个能拖拽的点。接下来要为每个点,加上拖拽响应的事件:
上面的代码中,使用了 convertFromPixel 这个 API。它是 convertToPixel 的逆向过程。myChart.convertFromPixel('grid', this.position) 表示把当前像素坐标转换成 grid 组件中直角坐标系的 dataItem 值。
最后,为了使 dom 尺寸改变时,图中的元素能自适应得变化,加上这些代码:
(二)
到此,拖拽的基本功能就完成了。但是想要更进一步得实时看到拖拽过程中,被拖拽的点的 data 值的变化状况,我们可以使用 tooltip 组件来实时显示这个值。但是,tooltip 有其默认的『显示』『隐藏』触发规则,在我们拖拽的场景中并不适用,所以我们还要手动定制 tooltip 的『显示』『隐藏』行为。
在最前面的 option 中添加 tooltip 的定义:
添加 tooltip 的自定义的『显示』『隐藏』策略:
这里使用了 dispatchAction 来显示隐藏 tooltip。用到了 showTip 、 hideTip 两个 action。
(三)
总结一下,全部的代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://echarts.baidu.com/dist/echarts.min.js"></script>
</head>
<body>
<div id="main" style="width: 600px;height:400px;"></div>
<script type="text/javascript">
var symbolSize = 20;
var data = [
[15, 0],
[-50, 10],
[-56.5, 20],
[-46.5, 30],
[-22.1, 40]
];
var myChart = echarts.init(
document.getElementById('main')
);
myChart.setOption({
tooltip: {
triggerOn: 'none',
formatter: function (params) {
return 'X: '
+ params.data[0].toFixed(2)
+ '<br>Y: '
+ params.data[1].toFixed(2);
}
},
xAxis: {
min: -100,
max: 80,
type: 'value',
axisLine: {onZero: false}
},
yAxis: {
min: -30,
max: 60,
type: 'value',
axisLine: {onZero: false}
},
series: [{
id: 'a',
type: 'line',
smooth: true,
symbolSize: symbolSize,
data: data
}]
});
myChart.setOption({
graphic: echarts.util.map(
data, eachDataItem
)
});
function eachDataItem(item, dataIndex) {
return {
type: 'circle',
position: myChart.convertToPixel(
'grid', item
),
shape: {
r: symbolSize / 2
},
invisible: true,
draggable: true,
ondrag: echarts.util.curry(
onPointDragging, dataIndex
),
onmousemove: echarts.util.curry(
showTooltip, dataIndex
),
onmouseout: echarts.util.curry(
hideTooltip, dataIndex
),
z: 100
};
}
window.addEventListener('resize', function () {
myChart.setOption({
graphic: echarts.util.map(data, eachUpdate)
});
});
function eachUpdate(item, dataIndex) {
return {
position: myChart.convertToPixel(
'grid', item
)
};
}
function showTooltip(dataIndex) {
myChart.dispatchAction({
type: 'showTip',
seriesIndex: 0,
dataIndex: dataIndex
});
}
function hideTooltip(dataIndex) {
myChart.dispatchAction({
type: 'hideTip'
});
}
function onPointDragging(dataIndex, dx, dy) {
data[dataIndex] = myChart.convertFromPixel(
'grid', this.position
);
myChart.setOption({
series: [{
id: 'a',
data: data
}]
});
}
</script>
</body>
</html>
有了这些基础,就可以定制更多的功能了,可以制作一个直角坐标系上的绘图板等等,可以发挥想象力。