2010-07-04 37 views
5

可能有人已經對這種困境相似的經歷,可以幫助我在這裏...裏面HTML5畫布:找出是否點擊座標是一個給定的矩形

基本上,我有一個canvas元素我使用

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

現在,我想要一些矩形的是熱點和響應單擊事件繪製在一個循環中幾個矩形。我可以使用event.layerXevent.layerY找出點擊事件的確切(x,y)。

鑑於我瞭解以下內容:

  • 確切的x,點擊
  • 在x,y,寬度和高度的每個矩形

我怎麼找到的ÿ如果點擊事件發生在某個矩形的邊界內
和,
哪個矩形發生了點擊事件0n?

有沒有像這樣的數學公式?

任何幫助將不勝感激,如果我不夠清晰,讓我知道...

感謝

編輯
有沒有通過所有要比循環沒有更好的辦法矩形並檢查它們的位置和尺寸?

回答

12

這是使用地圖時經常遇到的一般拓撲問題。

用於判定點是否是任何多邊形內(矩形,圓形,不規則形狀)的算法如下:

  • 從點被檢查構建在任何方向上的任何線直到的邊緣在您的多邊形位於

  • 如果線路在一些地方相交的任何多邊形邊界屏幕方面則是那個多邊形

  • 如果直線與任何多邊形相交an 甚至它的位置數是外部是那個多邊形。

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

注:

  • 線的方向是無關緊要的

  • 不會工作,如果一個多邊形被切斷在屏幕的一側,而不閉合

  • 如果多邊形切割自身,那麼算法可能會失敗,如果行 發生穿過截點(例如,在被視爲其中線精確地通過其中上部和下部 部件連接圖的一個 單個多邊形的圖8中連接)

+5

用於ASCII藝術! – 2012-10-12 03:14:07

1

粗略地說,你可以做這樣的:

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

假設我們正在處理的非負的寬度和高度:)

+0

難道還有比通過循環外沒有其他更好的辦法每個矩形和檢查尺寸......(嘆息!!) – ekhaled 2010-07-07 13:32:59

+0

你可以使用[bounding volume hierarchy(BVH)](http://en.wikipedia.org/wiki/Bounding_volume_hierarchy)之類的東西來分割空間和縮小需要檢查的矩形。這將需要一些預處理。 – tomit 2010-07-07 23:26:14

1

這可能是矯枉過正,但蛋糕JS會做的工作爲矩形和其他形狀。 Check out the demo

+0

他有一個完整的事件處理子系統,你是對的,這對我的需求有點矯枉過正。 – ekhaled 2010-07-07 13:32:15

5

我討厭張貼噸這裏的代碼,但這裏的一個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; 
} 
1

我最近創建了一個用於檢測鼠標在矩形上的點擊的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 
相關問題