W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
下面描述了一個(gè)能夠?qū)崿F(xiàn)拖拽的實(shí)例,該實(shí)例是在 Echarts 的基礎(chǔ)上的擴(kuò)展,我們可以通過該例子了解到怎么利用 Echarts 提供的 API 實(shí)現(xiàn)定制化的富有交互的功能。
上述實(shí)例達(dá)到的功能:您可以使用鼠標(biāo)拖拽圖中曲線上的點(diǎn),然后就能夠改變曲線的形狀。
上述實(shí)現(xiàn)拖拽的例子還很基礎(chǔ),但是學(xué)會(huì)上述例子之后我們能夠進(jìn)行更多的操作,比如在圖中可視化的編輯。
Echarts 本身沒有提供封裝好的拖拽改變圖表的功能,因?yàn)楝F(xiàn)在這個(gè)功能被認(rèn)為不具備通用性。因此開發(fā)者要實(shí)現(xiàn)這個(gè)功能就要使用 API ,這樣做的好處是能夠讓開發(fā)者按自己的需要進(jìn)行設(shè)置。
在這個(gè)例子中,基礎(chǔ)的圖表是一個(gè) 折線圖 (series-line)。詳細(xì)配置如下:
var symbolSize = 20;
// 這個(gè) data 變量在這里單獨(dú)聲明,在后面也會(huì)用到。
var data = [[15, 0], [-50, 10], [-56.5, 20], [-46.5, 30], [-22.1, 40]];
myChart.setOption({
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, // 為了方便拖拽,把 symbolSize 尺寸設(shè)大了。
data: data
}
]
});
折線點(diǎn)原本并沒有拖拽功能,需要我們?yōu)樗由希菏褂?graphic 組件,在每個(gè)點(diǎn)上面,覆蓋一個(gè)隱藏的可拖拽的圓點(diǎn),具體操作如下:
myChart.setOption({
// 聲明一個(gè) graphic component,里面有若干個(gè) type 為 'circle' 的 graphic elements。
// 這里使用了 echarts.util.map 這個(gè)幫助方法,其行為和 Array.prototype.map 一樣,但是兼容 es5 以下的環(huán)境。
// 用 map 方法遍歷 data 的每項(xiàng),為每項(xiàng)生成一個(gè)圓點(diǎn)。
graphic: echarts.util.map(data, function (dataItem, dataIndex) {
return {
// 'circle' 表示這個(gè) graphic element 的類型是圓點(diǎn)。
type: 'circle',
shape: {
// 圓點(diǎn)的半徑。
r: symbolSize / 2
},
// 用 transform 的方式對(duì)圓點(diǎn)進(jìn)行定位。position: [x, y] 表示將圓點(diǎn)平移到 [x, y] 位置。
// 這里使用了 convertToPixel 這個(gè) API 來得到每個(gè)圓點(diǎn)的位置,下面介紹。
position: myChart.convertToPixel('grid', dataItem),
// 這個(gè)屬性讓圓點(diǎn)不可見(但是不影響他響應(yīng)鼠標(biāo)事件)。
invisible: true,
// 這個(gè)屬性讓圓點(diǎn)可以被拖拽。
draggable: true,
// 把 z 值設(shè)得比較大,表示這個(gè)圓點(diǎn)在最上方,能覆蓋住已有的折線圖的圓點(diǎn)。
z: 100,
// 此圓點(diǎn)的拖拽的響應(yīng)事件,在拖拽過程中會(huì)不斷被觸發(fā)。下面介紹詳情。
// 這里使用了 echarts.util.curry 這個(gè)幫助方法,意思是生成一個(gè)與 onPointDragging
// 功能一樣的新的函數(shù),只不過第一個(gè)參數(shù)永遠(yuǎn)為此時(shí)傳入的 dataIndex 的值。
ondrag: echarts.util.curry(onPointDragging, dataIndex)
};
})
});
我們?cè)谏鲜龃a中使用了 convertToPixel 這個(gè) API,進(jìn)行了從 data 到像素坐標(biāo)的轉(zhuǎn)換,以確定每個(gè)圓點(diǎn)所處的位置,然后進(jìn)行圓點(diǎn)的繪制。
myChart.convertToPixel('grid', dataItem) 中的第一個(gè)參數(shù) ‘grid’ 表示 dataItem 在 grid(即直角坐標(biāo)系)這個(gè)組件中進(jìn)行的轉(zhuǎn)換。
像素坐標(biāo),就是以 Echarts 容器 dom element 的左上角為零點(diǎn)的以像素為單位的坐標(biāo)系中的坐標(biāo)。
注意:只有在初始化直角坐標(biāo)系(grid)后才能夠調(diào)用 myChart.convertToPixel('grid', dataItem)。
加入上述代碼之后,折線上就有了可拖拽的點(diǎn),接著我們要為每個(gè)圓點(diǎn)添加拖拽響應(yīng)的事件,具體操作如下:
// 拖拽某個(gè)圓點(diǎn)的過程中會(huì)不斷調(diào)用此函數(shù)。
// 此函數(shù)中會(huì)根據(jù)拖拽后的新位置,改變 data 中的值,并用新的 data 值,重繪折線圖,從而使折線圖同步于被拖拽的隱藏圓點(diǎn)。
function onPointDragging(dataIndex) {
// 這里的 data 就是本文最初的代碼塊中聲明的 data,在這里會(huì)被更新。
// 這里的 this 就是被拖拽的圓點(diǎn)。this.position 就是圓點(diǎn)當(dāng)前的位置。
data[dataIndex] = myChart.convertFromPixel('grid', this.position);
// 用更新后的 data,重繪折線圖。
myChart.setOption({
series: [{
id: 'a',
data: data
}]
});
}
我們?cè)谏厦娴拇a中,使用了 convertFromPixel 這個(gè) API。它是 convertToPixel 的逆向過程。
myChart.convertFromPixel('grid', this.position) :把當(dāng)前像素坐標(biāo)轉(zhuǎn)換成 grid 組件中直角坐標(biāo)系的 dataItem 值。
最后,為了使 dom 尺寸改變時(shí),圖中的元素能自適應(yīng)得變化,加入下述代碼:
window.addEventListener('resize', function () {
// 對(duì)每個(gè)拖拽圓點(diǎn)重新計(jì)算位置,并用 setOption 更新。
myChart.setOption({
graphic: echarts.util.map(data, function (item, dataIndex) {
return {
position: myChart.convertToPixel('grid', item)
};
})
});
});
到目前為止,我們已經(jīng)基本實(shí)現(xiàn)了拖拽功能。
現(xiàn)在,我們開始學(xué)習(xí)使用 tooltip 組件來實(shí)時(shí)顯示拖拽過程中被拖拽的點(diǎn)的 data 值的變化狀況。
注意:雖然 tooltip 有其默認(rèn)的顯示和隱藏的觸發(fā)規(guī)則,但是在我們的拖拽場景中不適用,因此需要手動(dòng)添加它們。
在上述代碼中分別添加如下定義:
myChart.setOption({
...,
tooltip: {
// 表示不使用默認(rèn)的『顯示』『隱藏』觸發(fā)規(guī)則。
triggerOn: 'none',
formatter: function (params) {
return 'X: ' + params.data[0].toFixed(2) + '<br>Y: ' + params.data[1].toFixed(2);
}
}
});
myChart.setOption({
graphic: echarts.util.map(data, function (item, dataIndex) {
return {
type: 'circle',
...,
// 在 mouseover 的時(shí)候顯示,在 mouseout 的時(shí)候隱藏。
onmousemove: echarts.util.curry(showTooltip, dataIndex),
onmouseout: echarts.util.curry(hideTooltip, dataIndex),
};
})
});
function showTooltip(dataIndex) {
myChart.dispatchAction({
type: 'showTip',
seriesIndex: 0,
dataIndex: dataIndex
});
}
function hideTooltip(dataIndex) {
myChart.dispatchAction({
type: 'hideTip'
});
}
這里使用了 dispatchAction 來顯示隱藏 tooltip。用到了 showTip、hideTip。
總結(jié)一下,全部的代碼如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="http://echarts.baidu.com/dist/echarts.min.js" rel="external nofollow" ></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, function (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, function (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>
在這些基礎(chǔ)上,我們可以實(shí)現(xiàn)更多的功能,例如可以添加 dataZoom 組件、可以制作一個(gè)直角坐標(biāo)系上的繪圖板等等。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: