美文网首页canvas绘图
canvas控件--折线图--区间选择功能(下)

canvas控件--折线图--区间选择功能(下)

作者: 王恩智 | 来源:发表于2017-07-11 14:46 被阅读27次

    上一篇,我们讨论了如何通过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完整版版在线示例及代码

    相关文章

      网友评论

        本文标题:canvas控件--折线图--区间选择功能(下)

        本文链接:https://www.haomeiwen.com/subject/ejzphxtx.html