Canvas 入门3 Click事件处理

传统的DOM的事件处理机制在Canvas里并不适应.Canvas是一个整体,无法给里面的某个图形增加Javascript事件。

由于事件只能达到Canvas元素这一层,所以,如果要识别点击发生在哪一个图形上,需要增加代码进行处理:

  • 给Canvas绑定事件
  • 事件发生时,检查事件对象的位置
  • 检查哪些图形覆盖了该位置

给Canvas元素绑定事件

cvs = document.getElementById('canvas');
cvs.addEventListener('click,function(e){

},false);

判断事件对象发生的位置

事件对象e的.layerX和layerY属性代表Canvas内部坐标系中的坐标。但这个属性可能会被废弃,所以要写兼容方法:

//该函数需要将canvas的position设置为absolute
       <canvas id="myCanvas" width="400" height="400" style="border:2px solid #eee;position:absolute"></canvas>

        <script>
            var cvs = document.getElementById('myCanvas');
            cvs.addEventListener('click',function(e){
                console.log(getEventPosition(e));
            },false);

            function getEventPosition(ev){
              var x, y;
              if (ev.layerX || ev.layerX == 0) {
                  x = ev.layerX;
                  y = ev.layerY;
              } else if (ev.offsetX || ev.offsetX == 0) { // Opera
                  x = ev.offsetX;
                  y = ev.offsetY;
              }
              return {x: x, y: y};
            }
        </script>

isPointInPath方法

用来判断当前上下文的图形是否覆盖了某个坐标。

  cvs = document.getElementById('mycanvas');
  ctx = canvas.getContext('2d');
  ctx.rect(10, 10, 100, 100);
  ctx.stroke();
  ctx.isPointInPath(50, 50); //true
  ctx.isPointInPath(5, 5); //false

事件结合isPointInPath

       <canvas id="myCanvas" width="400" height="400" style="border:2px solid #eee;position:absolute"></canvas>

        <script>
            var canvas = document.getElementById('myCanvas');
            var ctx = canvas.getContext('2d');
            ctx.rect(10,10,100,100);
            ctx.stroke();
            console.log(ctx.isPointInPath(50,50));

            canvas.addEventListener('click',function(e){
                console.log(getEventPosition(e));
                var p=getEventPosition(e);
                console.log(ctx.isPointInPath(p.x,p.y));
            },false);

            function getEventPosition(ev){
              var x, y;
              if (ev.layerX || ev.layerX == 0) {
                  x = ev.layerX;
                  y = ev.layerY;
              } else if (ev.offsetX || ev.offsetX == 0) { // Opera
                  x = ev.offsetX;
                  y = ev.offsetY;
              }
              return {x: x, y: y};
            }

        </script>

isPointInPath方法仅判断当前上下文环境中的路径,所以当Canvas里已经绘制了多个图形时,仅能以最后一个图形的上下文环境来判断事件
解决方案:当点击事件发生时,重绘所有图形,每绘制一个就使用isPointInPath方法,判断事件坐标是否在该图形覆盖范围内。

循环重绘和事件冒泡

为了实现循环重绘,要先将图形的基本参数先保存下来。

  <body>
    <canvas id="mycanvas" width="150" height="150"></canvas>

    <script type="text/javascript">
    arr = [
      {x:10, y:10, width:100, height:100},
      {x:110, y:110, width:100, height:100}
  ];
    var canvas = document.getElementById('mycanvas');
  var ctx = canvas.getContext('2d');
  
  function draw(){
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      arr.forEach(function(v){
          ctx.beginPath();
          ctx.rect(v.x, v.y, v.width, v.height);
          ctx.stroke();
      });
    }
    draw();
    </script>
  </body>

实现点击后重绘,并判断点击图形

  <body>
    <canvas id="mycanvas" width="150" height="150"></canvas>

    <script type="text/javascript">
    arr = [
      {x:10, y:10, width:100, height:100},
      {x:110, y:110, width:100, height:100}
  ];
    var canvas = document.getElementById('mycanvas');
  var ctx = canvas.getContext('2d');
  canvas.addEventListener('click', function(e){  
      p = getEventPosition(e);  
      var who=draw(p);  
      console.log('in',who);
    }, false);  
  function draw(p){
        console.log('click',p);
        var who=[];
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      arr.forEach(function(v,i){
          ctx.beginPath();
          ctx.rect(v.x, v.y, v.width, v.height);
          ctx.stroke();
            if(p && ctx.isPointInPath(p.x,p.y)){
                who.push(i);
            }
      });
        return who;
    }
    function getEventPosition(ev){  
      var x, y;  
      if (ev.layerX || ev.layerX == 0) {  
        x = ev.layerX;  
        y = ev.layerY;  
      } else if (ev.offsetX || ev.offsetX == 0) { // Opera  
        x = ev.offsetX;  
        y = ev.offsetY;  
      }  
      return {x: x, y: y};  
    }  
    draw();
    </script>
  </body>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程圈子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值