得到画布内每个矩形的点击事件?

时间:2011-02-16 09:46:29

标签: html5 canvas click

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

这是样本:

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

5 个答案:

答案 0 :(得分:23)

你基本上必须跟踪画布上矩形的位置,然后在画布上设置一个事件监听器。从那里你可以获取click事件的坐标并浏览所有矩形来测试'碰撞'。

以下是这样做的示例: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);
}

答案 1 :(得分:13)

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

有许多库可以跟踪在画布上绘制的对象的位置,并处理处理鼠标交互的所有复杂性。见EaselJSKineticJSPaper.jsFabric.js以及comparison 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

答案 2 :(得分:2)

我找到了一种方法,可以使用 clientX,clientY 代替offsetX / offsetY在mozilla中完成此工作。

此外,如果您的画布超出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/

答案 3 :(得分:0)

如果你想在画布上支持多个矩形并处理它的点击事件,请使用下面的功能......由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;
} 

答案 4 :(得分:0)

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

<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/