【问题标题】:get click event of each rectangle inside canvas?获取画布内每个矩形的点击事件?
【发布时间】:2011-06-28 05:49:08
【问题描述】:

我不知道如何在每个矩形上注册点击事件。

这里是示例:

http://jsfiddle.net/9WWqG/1/

【问题讨论】:

标签: html canvas click


【解决方案1】:

您基本上必须跟踪矩形在画布上的位置,然后在画布本身上设置一个事件侦听器。从那里您可以获取点击事件的坐标并遍历所有矩形以测试“碰撞”。

这是一个这样做的例子:http://jsfiddle.net/9WWqG/2/

html:

<canvas id="myCanvas" width="300" height="150">
</canvas>

javascript:

// get canvas element.
var elem = document.getElementById('myCanvas');

function collides(rects, x, y) {
    var isCollision = false;
    for (var i = 0, len = rects.length; i < len; i++) {
        var left = rects[i].x, right = rects[i].x+rects[i].w;
        var top = rects[i].y, bottom = rects[i].y+rects[i].h;
        if (right >= x
            && left <= x
            && bottom >= y
            && top <= y) {
            isCollision = rects[i];
        }
    }
    return isCollision;
}

// check if context exist
if (elem && elem.getContext) {
    // list of rectangles to render
    var rects = [{x: 0, y: 0, w: 50, h: 50},
                 {x: 75, y: 0, w: 50, h: 50}];
  // get context
  var context = elem.getContext('2d');
  if (context) {

      for (var i = 0, len = rects.length; i < len; i++) {
        context.fillRect(rects[i].x, rects[i].y, rects[i].w, rects[i].h);
      }

  }

    // listener, using W3C style for example    
    elem.addEventListener('click', function(e) {
        console.log('click: ' + e.offsetX + '/' + e.offsetY);
        var rect = collides(rects, e.offsetX, e.offsetY);
        if (rect) {
            console.log('collision: ' + rect.x + '/' + rect.y);
        } else {
            console.log('no collision');
        }
    }, false);
}

【讨论】:

  • 感谢您的回答..但是当画布中有多个矩形时,您的碰撞功能不起作用...我进行了如下修改并且它有效...
  • 你怎么能用圆圈什么的?
  • @user10124491,检查点击距离圆心的距离。如果该距离小于圆的半径,则它在内部。
【解决方案2】:

这是一个老问题,但发布时曾经很难做到的事情现在变得容易多了。

有许多库可以跟踪在画布上绘制的对象的位置,并处理处理鼠标交互的所有复杂性。见EaselJS, KineticJS, Paper.jsFabric.jscomparison of canvas libraries 了解更多信息。

您还可以采取不同的方法并使用 RaphaëlgRaphaël 拥有一个使用 SVG 和 VML 而不是画布并且甚至可以在 IE6 上运行的解决方案。

您的示例改为使用 Raphaël 将如下所示:

var r = Raphael(0, 0, 300, 150);

r.rect(0, 0, 50, 50)
    .attr({fill: "#000"})
    .click(function () {
        alert('first rectangle clicked');
     });

r.rect(75, 0, 50, 50)
    .attr({fill: "#000"})
    .click(function () {
        alert('second rectangle clicked');
     });

DEMO

2015 年更新

您还可以使用ART,这是一个用于 HTML5 画布的保留模式矢量绘图 API - 请参阅 this answer 了解更多信息。

【讨论】:

  • 我在一个页面上有 4 个动态甜甜圈图,它们是动态创建的,我需要在每个可以点击的中心放置一个可点击的文本。请问有什么想法吗?提问:stackoverflow.com/questions/38243032/…
【解决方案3】:

我找到了一种在 mozilla 中使用 clientX,clientY 代替 offsetX/offsetY 的方法。

此外,如果您的画布超出innerHeight,并使用滚动,请将window.pageYOffset 添加到e.clientY。如果您的画布超出宽度,则以同样的方式进行。

另一个例子在我的 github:https://github.com/michaelBenin/fi-test

这里是另一个解释这一点的链接:http://eli.thegreenplace.net/2010/02/13/finding-out-the-mouse-click-position-on-a-canvas-with-javascript/

【讨论】:

    【解决方案4】:

    如果您想在画布中支持多个矩形并处理其点击事件,请使用以下函数.....Matt King给出的修改逻辑。

        function collides(myRect, x, y) {
        var isCollision = false;
        for (var i = 0, len = myRect.length; i < len; i++) {
            var left = myRect[i].x, right = myRect[i].x+myRect[i].w;
            var top = myRect[i].y, bottom = myRect[i].y+myRect[i].h;
           if ((left + right) >= x
                && left <= x
                && (top +bottom) >= y
                && top <= y) {
                isCollision = json.Major[i];
            }
            }
        }
        return isCollision;
    } 
    

    【讨论】:

      【解决方案5】:

      如果您想在画布中支持多个矩形并处理其点击事件,请使用以下函数

      <canvas id="myCanvas" width="1125" height="668" style="border: 3px solid #ccc; margin:0;padding:0;" />
      
        var elem = document.getElementById('myCanvas'),
          elemLeft = elem.offsetLeft,
          elemTop = elem.offsetTop,
          context = elem.getContext('2d'),
          elements = [];
      
          // Add event listener for `click` events.
          elem.addEventListener('click', function (event) {
             // var leftWidth = $("#leftPane").css("width")
      
            //  var x = event.pageX - (elemLeft + parseInt(leftWidth) + 220),
             //     y = event.pageY - (elemTop + 15);
      
                  var x = event.pageX - elemLeft,
              y = event.pageY - elemTop;
      
              elements.forEach(function (element) {
                  if (y > element.top && y < element.top + element.height && x > element.left && x < element.left + element.width) {
                      alert(element.text);
                  }
              });
          }, false);
      
      
      
          // Set the value content (x,y) axis
          var x = 15, y = 20, maxWidth = elem.getAttribute("width"),
              maxHeight = elem.getAttribute("height"), type = 'TL',
              width = 50, height = 60, text = "", topy = 0, leftx = 0;
      
      
      
          for (i = 1; i <= 15; i++) {
              y = 10;
              for (j = 1; j <= 6; j++) {
                  width = 50, height = 60
                  switch (j) {
                      case 1:
                          type = 'TL'; // Trailer
                          height = 60;
                          width = 85;
                          text = i + 'E';
                          break;
                      case 2:
                          type = 'DR'; // Door
                          height = 35;
                          width = 85;
                          text = i;
                          break;
                      case 3:
                          type = 'FL'; // Floor
                          height = 30;
                          width = 40;
                          break;
                      case 4:
                          type = 'FL'; // Floor
                          height = 30;
                          width = 40;
                          y -= 10;
                          break;
                      case 5:
                          type = 'DR'; // Door
                          height = 35;
                          width = 85;
                          text = i*10 + 1;
                          y = topy;
                          break;
                      case 6:
                          type = 'TL'; // Trailer
                          height = 60;
                          width = 85;
                          text = i + 'F';
                          y += 5;
                          break;
                  }
      
                  topy = y;
                  leftx = x;
                  if (type == 'FL') {
                      for (k = 1; k <= 12; k++) {
                          elements.push({
                              colour: '#05EFFF',
                              width: width,
                              height: height,
                              top: topy,
                              left: leftx,
                              text: k,
                              textColour: '#fff',
                              type: type
                          });
      
                          if (k % 2 == 0) {
                              topy = y + elements[j - 1].height + 5;
                              leftx = x;
                              y = topy;
                          }
                          else {
                              topy = y;
                              leftx = x + elements[j - 1].width + 5;
                          }
                      }
                      x = leftx;
                      y = topy;
                  }
                  else {
                      elements.push({
                          colour: '#05EFFF',
                          width: width,
                          height: height,
                          top: y,
                          left: x,
                          text: text,
                          textColour: '#fff',
                          type: type
                      });
                  }
      
                  //get the y axis for next content
                  y = y + elements[j-1].height + 6
                  if (y >= maxHeight - elements[j-1].height) {
                      break;
                  }
              }
              //get the x axis for next content
              x = x + elements[0].width + 15
              if (x >= maxWidth - elements[0].width) {
                  break;
              }
          }
      
          // Render elements.
          elements.forEach(function (element) {
              context.font = "14pt Arial";
              context.strokeStyle = "#000";
              context.rect(element.left, element.top, element.width, element.height);
              if (element.type == 'FL') {
                  context.fillText(element.text, element.left + element.width / 4, element.top + element.height / 1.5);
              }
              else {
                  context.fillText(element.text, element.left + element.width / 2.5, element.top + element.height / 1.5);
              }
              context.lineWidth = 1;
              context.stroke()
          });
      

      这是一个这样做的例子:http://jsfiddle.net/BmeKr/1291/

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-05
        • 2022-01-05
        • 1970-01-01
        • 1970-01-01
        • 2023-04-09
        • 1970-01-01
        相关资源
        最近更新 更多