上一篇彼棍,我們討論了如何通過canvas繪制一個折線圖
接下來,我們將給這個折線圖實(shí)現(xiàn)鼠標(biāo)交互效果
首先咐扭,鼠標(biāo)在我們的折線圖上移動時子寓,我們要一個藍(lán)色的豎線跟隨鼠標(biāo)移動
要實(shí)現(xiàn)這個效果,我們一步一步來
1辜羊、我們需要在canvas的mousemove事件方法中踏兜,根據(jù)鼠標(biāo)位置clientX/Y词顾,和容器的top/left值,計(jì)算出鼠標(biāo)所在處的canvas坐標(biāo)碱妆;
2肉盹、根據(jù)鼠標(biāo)坐標(biāo)判斷鼠標(biāo)是否在折線圖上,如果鼠標(biāo)在折線圖上疹尾,將鼠標(biāo)x軸坐標(biāo)(即橫向坐標(biāo))保存在mousemovePositionx變量中上忍,如果鼠標(biāo)不在折線圖上,將mousemovePositionx變量設(shè)置為null;
3纳本、drow方法中判斷mousemovePositionx變量是否為null窍蓝,若不為null,則根據(jù)mousemovePositionx的值繪制藍(lán)色線段
在線展示及代碼
然后繁成,我們分解一下鼠標(biāo)拖動選擇時間區(qū)間這個操作
1吓笙、鼠標(biāo)按下; 2巾腕、鼠標(biāo)移動面睛; 3、鼠標(biāo)抬起
實(shí)際上我們只需要在鼠標(biāo)按下時記錄鼠標(biāo)按下的位置尊搬,鼠標(biāo)抬起時叁鉴,根據(jù)鼠標(biāo)抬起位置和之前記錄的鼠標(biāo)按下的位置,便可以得到拖拽動作選擇的區(qū)間
但是這樣做佛寿,鼠標(biāo)移動時沒有任何交互效果
為了更好的用戶體驗(yàn)幌墓,我們可以在鼠標(biāo)移動方法中,通過鼠標(biāo)位置與鼠標(biāo)按下位置冀泻,將已選擇區(qū)間記錄下來克锣,供draw方法繪制相應(yīng)交互效果
mousedown = e => {
const x = e.clientX - L,
y = e.clientY - T;
if (y > chartTop && y < chartBottom && x > chartLeft && x < chartRight ) {
mouseDownZB = x;
} else {
mouseDownZB = null;
}
}
mousemove = e => {
const x = e.clientX - L,
y = e.clientY - T;
if (y > chartTop && y < chartBottom && x > chartLeft && x < chartRight ) {
mouseMovePosition = x;
if (mouseDownZB !== null) {
mouseSelected = [mouseDownZB, x];
} else {
mouseSelected = null;
}
} else {
mouseMovePosition = null;
}
}
mouseup = e => {
mouseDownZB = null;
mouseSelected = null;
}
drawOther = () => {
...
if (mouseSelected !== null) {
ctx.save();
ctx.fillStyle = "rgba(55, 183, 248, 0.5)";
ctx.beginPath();
ctx.rect(mouseSelected[0], chartTop, Math.abs(mouseSelected[0] - mouseSelected[1]), ylength);
ctx.fill();
}
}
上面這段代碼,實(shí)現(xiàn)了鼠標(biāo)拖拽選擇區(qū)間腔长,mouseup中將mouseDownZB袭祟,mouseSelected兩個變量置為null,此時我們已經(jīng)選擇了一個區(qū)間捞附,需要將沒有選擇的區(qū)間置為灰色巾乳,
因此我需要在將變量mouseSelected置為null前,賦值變量hasSelected = mouseSelected
drawOther方法中添加代碼
if (hasSelected !== null) {
ctx.save();
ctx.strokeStyle = '#CCCCCC';
ctx.fillStyle = 'rgba(230, 230, 230, 0.8)';
ctx.beginPath();
ctx.rect(chartLeft, chartTop, hasSelected[0] - chartLeft, ylength);
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.rect(hasSelected[1], chartTop, chartRight - hasSelected[1], ylength);
ctx.fill();
ctx.stroke();
ctx.restore();
}
查看代碼鸟召,細(xì)心的同學(xué)可能已經(jīng)發(fā)現(xiàn)了胆绊,第一次選擇區(qū)間后,再選擇區(qū)間欧募,偶爾在上部會出現(xiàn)一道灰線压状,如下圖
這個問題與canvas劃線的方式有關(guān),有興趣的同學(xué)自行百度,這里我們只需修改一下清除畫布方法即可
ctx.clearRect(chartLeft, chartTop - 1, xlength, ylength + 1);//清除變動區(qū)域
標(biāo)記出已選擇部分還不夠种冬,我們需要計(jì)算出選擇區(qū)域起止點(diǎn)具體時間
data[Math.ceil((hasSelected[0] - chartLeft) / xstep)].date;
data[Math.floor((hasSelected[1] - chartLeft) / xstep)].date
這樣一個簡單的附帶區(qū)間選擇的折線圖就完成了
查看es6簡化版在線示例及代碼
查看es5完整版版在線示例及代碼