代码之家  ›  专栏  ›  技术社区  ›  ekhaled

HTML5画布:查看单击坐标是否在给定矩形内

  •  5
  • ekhaled  · 技术社区  · 15 年前

    也许有人在这个困境上也有过类似的经历,可以帮助我走出困境…

    基本上,我有一个画布元素,在它上面我用

    context.fillRect (x, y, width, height)
    

    现在,我希望一些矩形成为热点并响应单击事件。我可以使用 event.layerX event.layerY .

    鉴于我知道以下情况:

    • 点击的精确x,y
    • 每个矩形的x、y、宽度和高度

    如何确定单击事件是否发生在某个矩形的周界内 ?
    而且,
    单击事件发生在哪个矩形0n?

    这有数学公式吗?

    任何帮助都会非常感谢,如果我不够清楚,请告诉我…

    谢谢

    编辑
    有没有比在所有矩形中循环并检查它们的位置和尺寸更好的方法?

    5 回复  |  直到 8 年前
        1
  •  12
  •   Avron Polakow    14 年前

    这是使用地图时经常遇到的一般拓扑问题。

    确定点是否在任何多边形(矩形、圆形、不规则形状)内的算法如下:

    • 从被检查的点开始,在任何方向上构造任何线,直到多边形所在的屏幕区域的边缘。

    • 如果该线与任何多边形边界相交, 古怪的 那么有多少地方呢 在内部 那个多边形

    • 如果该线与任何多边形边界相交, 即使 它的位置数 外部 那个多边形。

             ------------
             |           |
             |        o--|-------------------    1 intersection: inside
             |           |
             -------------
             ------------
             |           |
      o------|-----------|-------------------    2 intersections: outside
             |           |
             -------------
      

    笔记:

    • 线的方向无关

    • 如果在屏幕侧面切割多边形而没有闭合,则不起作用

    • 如果多边形割断了自身,那么如果该线 恰好通过了切割点(如图8中被认为是 一个多边形,直线正好穿过上面和下面 图中各部分连接)

        2
  •  5
  •   prauchfuss    14 年前

    我不想在这里发布大量的代码,但这里有一个JS类可以帮助您…

    function Point(x,y){
        this.x=x;
        this.y=y;
    }
    
    function Polygon(){
        this.points=[];
        this.x_min=undefined;
        this.x_max=undefined;
        this.y_min=undefined;
        this.y_max=undefined;
    
        this.add = function(p){
            this.points=this.points.concat(p);
            if (p.x<this.x_min){this.x_min=p.x;}
            if (p.x>this.x_max){this.x_max=p.x;}
            if (p.y<this.y_min){this.y_min=p.y;}
            if (p.y>this.y_min){this.y_max=p.y;}
        }
    
        this.pointInPoly = function(p){
            var j=(this.points.length-1);  //start by testing the link from the last point to the first point
            var isOdd=false;
    
            //check the bounding box conditions
            if (p.x < this.x_min || p.x > this.x_max || p.y < this.y_min || p.y > this.y_max){
                return false;
            }
    
            //if necessary use the line crossing algorithm
            for(var i=0; i<this.points.length; i++){
                if ((this.points[i].y<p.y && this.points[j].y>=p.y) ||  
                    (this.points[j].y<p.y && this.points[i].y>=p.y)) {
                        if (this.points[i].x+(p.y-this.points[i].y)/(this.points[j].y-
                            this.points[i].y)*(this.points[j].x-this.points[i].x)<p.x)
                        { isOdd=(!isOdd);} }
                j=i;
            }
            return isOdd;
        }
    }
    

    ps:您需要使用如下函数(其中e是您的单击事件)将单击事件转换为本地坐标:

    function getPosition(e){
        var p = new Point();
        if (e.pageX != undefined && e.pageY != undefined) {
            p.x = e.pageX;
            p.y = e.pageY;
         }
         else {
            p.x = e.clientX + document.body.scrollLeft +
                    document.documentElement.scrollLeft;
            p.y = e.clientY + document.body.scrollTop +
                    document.documentElement.scrollTop;
        }
        p.x -= gCanvas.offsetLeft;
        p.y -= gCanvas.offsetTop;
    
    
        return p;
    }
    
        3
  •  1
  •   tomit    15 年前

    大致上,您可以这样做:

    var click_x = event.layerX;
    var click_y = event.layerY;
    
    for ( var i = 0; i < rects.length; i++ ) {
        var rect = rects[i];
        if ( click_x >= rect.x && click_x <= rect.x + rect.width
        &&   click_y >= rect.y && click_y <= rect.y + rect.height ) {
            // The click was inside the rectange
        }
    }
    

    假设我们处理的是非负宽度和高度:)

        4
  •  1
  •   brainjam    15 年前

    这可能有点过分,但CakeJS将用于矩形和其他形状。 Check out the demo .

        5
  •  1
  •   Josh from Qaribou    8 年前

    我最近创建了一个用于检测矩形上鼠标单击的API。这是非常基本的,但它应该能解决你的问题
    你可以找到它 here .
    注意:它目前没有对按钮的文本支持,但它确实支持一些基本样式。
    文档: Here 代码:

    function canvasButton(x, y, w, h, style , text) {
      this.style = style
      this.x = x || 0;
      this.y = y || 0;
      this.w = w || 1;
      this.h = h || 1;
      this.fill = style.default.fill ;
      this.text = text || undefined;
      this.onclick = function() {alert("Click! Make sure to add the onclick listener to your button!")}
      this.mouseup = function() {alert("Mouseup! Make sure to add the mouseup listener to your button!")}
      this.addListener = function() {
        var buttonX = this.x;
        var buttonY = this.y;
        var buttonWidth = this.w;
        var buttonHeight = this.h;
        var onclick = this.onclick
        var mouseup = this.mouseup
        var styles = this.style
        var draw = this.draw
        var ctx = this.ctx
        this.ctx.canvas.addEventListener('mousedown',function(e){
            var click_x = e.clientX;
            var click_y = e.clientY;
            if ( click_x >= buttonY && click_x <= buttonX + buttonWidth && click_y >= buttonY && click_y <= buttonY + buttonHeight ) {  
                onclick()
                ctx.fillStyle = style.active.fill
                ctx.fillRect(buttonX, buttonY, buttonWidth, buttonHeight);
            }
        })
        this.ctx.canvas.addEventListener('mouseup',function(e) {
            var click_x = e.clientX;
            var click_y = e.clientY;
            if ( click_x >= buttonY && click_x <= buttonX + buttonWidth && click_y >= buttonY && click_y <= buttonY + buttonHeight ) {  
                mouseup()
                ctx.fillStyle = style.default.fill
                ctx.fillRect(buttonX, buttonY, buttonWidth, buttonHeight);
    
            }
    
        })
      }
    
    }
    
    // Draws this shape to a given context
    canvasButton.prototype.draw = function(ctx) {
      this.ctx = ctx
      ctx.fillStyle = this.fill;
      ctx.font = this.font
      ctx.fillRect(this.x, this.y, this.w, this.h);
      ctx.fillText(this.text,this.x,this.y)
      this.addListener();
    }
    
    
    //Use it like this:
    var start = new canvasButton(x,y,height,width,{ // Styles
        "default": {
            "fill":"#765",
    
        }, 
        "active": {
            "fill":"#876",
    
        } 
    })
    //Event Listeners
    start.mousedown = function() {
    
    }
    start.mouseup = function() {
    
    }
    start.draw(document.getElementById("canvas").getContext("2d")); // Draw to canvas