canvas控件--折線圖--區間選擇功能(下)

上一篇,我們討論了如何通過canvas繪制一個折線圖
接下來,我們將給這個折線圖實現鼠標交互效果

首先,鼠標在我們的折線圖上移動時,我們要一個藍色的豎線跟隨鼠標移動
要實現這個效果,我們一步一步來
1、我們需要在canvas的mousemove事件方法中,根據鼠標位置clientX/Y,和容器的top/left值,計算出鼠標所在處的canvas坐標;
2、根據鼠標坐標判斷鼠標是否在折線圖上,如果鼠標在折線圖上,將鼠標x軸坐標(即橫向坐標)保存在mousemovePositionx變量中,如果鼠標不在折線圖上,將mousemovePositionx變量設置為null;
3、drow方法中判斷mousemovePositionx變量是否為null,若不為null,則根據mousemovePositionx的值繪制藍色線段
在線展示及代碼

然后,我們分解一下鼠標拖動選擇時間區間這個操作
1、鼠標按下; 2、鼠標移動; 3、鼠標抬起
實際上我們只需要在鼠標按下時記錄鼠標按下的位置,鼠標抬起時,根據鼠標抬起位置和之前記錄的鼠標按下的位置,便可以得到拖拽動作選擇的區間
但是這樣做,鼠標移動時沒有任何交互效果
為了更好的用戶體驗,我們可以在鼠標移動方法中,通過鼠標位置與鼠標按下位置,將已選擇區間記錄下來,供draw方法繪制相應交互效果

       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();
            }
        }

上面這段代碼,實現了鼠標拖拽選擇區間,mouseup中將mouseDownZB,mouseSelected兩個變量置為null,此時我們已經選擇了一個區間,需要將沒有選擇的區間置為灰色,
因此我需要在將變量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();
}

查看代碼,細心的同學可能已經發現了,第一次選擇區間后,再選擇區間,偶爾在上部會出現一道灰線,如下圖


這個問題與canvas劃線的方式有關,有興趣的同學自行百度,這里我們只需修改一下清除畫布方法即可
ctx.clearRect(chartLeft, chartTop - 1, xlength, ylength + 1);//清除變動區域

標記出已選擇部分還不夠,我們需要計算出選擇區域起止點具體時間

data[Math.ceil((hasSelected[0] - chartLeft) / xstep)].date;
data[Math.floor((hasSelected[1] - chartLeft) / xstep)].date

這樣一個簡單的附帶區間選擇的折線圖就完成了
查看es6簡化版在線示例及代碼
查看es5完整版版在線示例及代碼

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容