zoukankan      html  css  js  c++  java
  • 如何实现Canvas图像的拖拽、点击等操作

    上一篇Canvas的博文写完后,有位朋友希望能对Canvas绘制出来的图像进行点击、拖拽等操作,因为Canvas绘制出的图像能很好的美化。好像是想做炉石什么的游戏,我也没玩过。

    Canvas在我的理解中就好像在一张画布上绘制图像,它只能看到却“摸”不到,那要如何进行操作呢。我不知道网上是怎么做的,这里用自己的想法做了个DEMO分享给大家。

    思路:

    虽然Canvas不能拖拽,但div可以拖拽,那怎么把二者结合起来呢。初步想法是将一个与Canvas图像大小差不多的div覆盖在其上,在拖拽div时将获取的光标坐标修正后传给Canvas绘制函数并刷新图像的位置。

    既然要覆盖,先做些准备工作:

    1.将div与Canvas画布均position:absolute,否则无法重叠。

    2.将div的z-index值设置大点,保证其在Canvas画面之上。

    准备工作完成后,我们先来看div的拖拽:

        var divObj=document.getElementById("cover");
        var moveFlag=false;
    
            divObj.onmousedown=function(e){
            moveFlag=true;
            var clickEvent=window.event||e;
            var mwidth=clickEvent.clientX-divObj.offsetLeft;
            var mheight=clickEvent.clientY-divObj.offsetTop;
            document.onmousemove=function(e){
                var moveEvent=window.event||e;
                if(moveFlag){
                    divObj.style.left=moveEvent.clientX-mwidth+"px";
                    divObj.style.top=moveEvent.clientY-mheight+"px";
                    divObj.onmouseup=function(){
                        moveFlag=false;
                    }
                }
            }
        };

    来解读下这段代码:首先获取div对象,设置拖拽标志moveFlage,当onmousedown时为true表示可以拖动,当onmouseup时为false表示不能拖动了。

          var clickEvent=window.event||e;
          var mwidth=clickEvent.clientX-divObj.offsetLeft;
          var mheight=clickEvent.clientY-divObj.offsetTop;

    这三行代码是为了修正光标位置。当点击时,记录下光标在div上的位置。mwidth和mheight表示光标落点相对于div左边和上边的距离。如果不加修正:

    这就是不加修正的结果,当光标点下时,div的坐标即左上角会与光标坐标一致。

    修正后:

    点击时光标总会“粘”在div某点上。

    接下来绘制图片:

    首先定义全局变量X和Y,它们是为了实时更新图像的绘制坐标。

     var ctx=document.getElementById("myCanvas").getContext("2d");
     var img=document.getElementById("myImg");
        function drawImg(){
            ctx.clearRect(0,0,1000,500);
            ctx.beginPath();
            ctx.drawImage(img,X,Y);
            ctx.closePath();
            ctx.stroke();
        }
    
        window.onload=function(){
            setInterval(drawImg,1);
        }

    获取“画笔”,获取图片对象。这里setInterval循环执行绘制图片的函数,以刷新图片的位置,setInterval的间隔值越小,拖拽起来越“流畅”。

    同时别忘了clearRect,当图片移动到下一个位置时,清除上一个位置的图片,参数为Canvas画布的坐标和尺寸。

    在拖拽时将修正后的光标坐标传给X、Y:

     X=moveEvent.clientX-mwidth;
     Y=moveEvent.clientY-mheight;

    最后加上div和图像的活动范围:

    if(moveEvent.clientX<=mwidth){
            divObj.style.left=0+"px";
            X=0;
    }
    if(parseInt(divObj.style.left)+divObj.offsetWidth >=1000){
            divObj.style.left=1000 - divObj.offsetWidth+"px";
            X=1000 - divObj.offsetWidth;
    }
    if(moveEvent.clientY<=mheight){
            divObj.style.top=0+"px";
            Y=0;
    }
    if(parseInt(divObj.style.top)+divObj.offsetHeight>=500){
           divObj.style.top=500-divObj.offsetHeight+"px";
           Y=500-divObj.offsetHeight;
    }

    这个就看个人的要求了,注意是要同时限定div和图片的活动范围。1000与500为本例的画布大小,如果是在整个页面里活动就换成innerWidth或innerHeight。

    彻底隐藏div看看效果:

    最后说下点击事件,这里要注意的是在拖拽的过程中onmousedown与onmouseup二者就构成了一个click过程,但我们不希望在拖拽结束后触发点击事件。

    这里有个比较简单的办法,定义一个clickFlag默认为false,当onmousedown时设为true,若进行了onmousemove事件时设为false。

    在最后onmouseup时判断clickFlag的值,为true时才触发点击事件。也就是说当你按下鼠标时,只有不发现移动,松开鼠标时才会触发点击事件。

    整理后的JS代码:

    //    绘制图片坐标
        var X=0;
        var Y=0;
    //    js部分
        var divObj=document.getElementById("cover");
        var moveFlag=false;
    //区别moueseup与click的标志
        var clickFlag=false;
    //    拖拽函数
        divObj.onmousedown=function(e){
            moveFlag=true;
            clickFlag=true;
            var clickEvent=window.event||e;
            var mwidth=clickEvent.clientX-divObj.offsetLeft;
            var mheight=clickEvent.clientY-divObj.offsetTop;
            document.onmousemove=function(e){
                clickFlag=false;
                var moveEvent=window.event||e;
                if(moveFlag){
                    divObj.style.left=moveEvent.clientX-mwidth+"px";
                    divObj.style.top=moveEvent.clientY-mheight+"px";
    ////              将鼠标坐标传给Canvas中的图像
                    X=moveEvent.clientX-mwidth;
                    Y=moveEvent.clientY-mheight;
    ////              下面四个条件为限制div以及图像的活动边界
                    if(moveEvent.clientX<=mwidth){
                        divObj.style.left=0+"px";
                        X=0;
                    }
                    if(parseInt(divObj.style.left)+divObj.offsetWidth >=1000){
                        divObj.style.left=1000 - divObj.offsetWidth+"px";
                        X=1000 - divObj.offsetWidth;
                    }
                    if(moveEvent.clientY<=mheight){
                        divObj.style.top=0+"px";
                        Y=0;
                    }
                    if(parseInt(divObj.style.top)+divObj.offsetHeight>=500){
                        divObj.style.top=500-divObj.offsetHeight+"px";
                        Y=500-divObj.offsetHeight;
                    }
                    divObj.onmouseup=function(){
                        moveFlag=false;
                        if(clickFlag){
                            alert("点击生效");
                        }
                    }
                }
            }
        };

    本例到此结束,更多功能大家有兴趣可以自己开发,感谢您的浏览,也感谢每个对我这菜鸟提意见的人。

  • 相关阅读:
    面向对象进阶----->反射 getattr 和hasattr方法
    封装和 property方法
    C/S与B/S区别
    BIO、NIO和AIO
    ArrayList、Vector、LinkedList的区别
    AOP代理模式
    Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以implements(实 现)interface(接口
    Spring常见面试题及答案解析
    数据库优化
    事物的理解
  • 原文地址:https://www.cnblogs.com/ghost-xyx/p/3833179.html
Copyright © 2011-2022 走看看