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控件--折线图--区间选择功能(下)_第1张图片

这个问题与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完整版版在线示例及代码

你可能感兴趣的:(canvas控件--折线图--区间选择功能(下))