javascript - 如何有效地检查鼠标是否位于 HTML5 Canvas 中的许多(120)个不同区域?

标签 javascript canvas onclick html5-canvas mouseevent

我有一个包含 120 个不同点的极坐标图(参见图片)。我想做到这一点,以便如果用户单击或悬停在其中一个点上,就会显示该点的坐标。我有一个名为 pointCooperatives 的数组,它存储每个点的每个 Canvas 坐标,如下所示:

[[x1, y1], [x2, y2] ... [x120, y120]]

这就是我捕获鼠标坐标的方式(稍后我可能会更改为单击):

document.onmousemove = function(e) {
    var x = e.clientX;
    var y = e.clientY;
}

我原本打算用一个公式来检查鼠标是否在某个区域(使用距离公式)或者将其全部简化为一个圆。不管怎样,这都需要我有 120 个不同的 if 语句来检查这一点。我觉得这效率低下而且可能很慢。还有其他方法可以做到这一点吗?

Polar Graph with Points

编辑:

为了提供更多信息,这些点将不可拖动。我计划在单击的点附近显示类似工具提示的内容,其中将显示该点的极坐标。

编辑2:

使用下面发布的代码并在 map 上的“可点击”位置绘制一个矩形后,我得到了这张图像。我不希望点击检测是完美的,但这在 pi/3 之后还很遥远。任何想法如何解决这一问题?我使用此代码生成黑点:

for(var x = 0; x < WIDTH*2/3; x++){
        for(var y = 0; y < HEIGHT; y++){
          var mp = realToPolar(x, y);//converts canvas x and y into polar
          if(checkRadialDistance(mp[0], mp[1])){ //returns true if in bounds
            ctx.fillRect(x, y, 1, 1);
          }
        }
      }

使用常量仍然会生成相同的图案,只是厚度不同。 checkRadialDistance 只是重命名的 checkr 函数,内部调用 checkrtenter image description here

JSBIN请记住,屏幕的宽度必须大于高度才能正常工作。

mt-rt生成的图像。后来我做了一个小的编辑,以便当 theta = 0 时覆盖整个圆。

enter image description here

最佳答案

编辑:我(接受的)答案很糟糕。这更正了它:

假设 r 为 1 到 5。将鼠标笛卡尔 mx,my 转换为极坐标 mr,mt。首先检查 mr 是否接近 5 个半径中的 1 个。功能检查器就是这样做的。如果接近,则检查 mt 是否接近 24 theta 中的 1。函数 checkt 就是这样做的。复杂之处在于,atan2 函数在点所在的 pi 弧度处不连续,因此在没有点的 -pi/24 弧度处不连续。

“接近”值为 pi/24,因为 r=1 处两个相邻点之间的弧距将为 pi/12。

var del = 1*Math.PI/24*.7; // for example

function xy2rt(xy) { // to polar cordinates
  var rt = [];
  rt.push(Math.sqrt(xy[0]*xy[0]+xy[1]*xy[1])); // r
  var zatan = Math.atan2(xy[1], xy[0]);
  // make the discontinuity at -pi/24
  if (zatan < -Math.PI/24) zatan += 2*Math.PI; 
  rt.push(zatan); // theta
  return rt;
}
function checkr() { // check radial distance
  for (var pr=1; pr<=5; pr+=1) { // 5 radii
    if (Math.abs(mr-pr) < del) { checkt(pr); break; }
  }
}  
function checkt(pr) { // check theta
  var pt;
  for (var ipt=0; ipt<24; ipt+=1) { // 24 thetas
    pt = ipt / 24 * 2 * Math.PI; 
    if (Math.abs(mt-pt) < del/pr) { 
      // is close -- do whatever
      break;
    }
  }
}

我的问题是在检查弧距时,我使用了 mr 和 pr,而应该只使用 pr。 OP 通过处理 Canvas 上的每个像素发现了我的错误,并发现存在问题。我还处理了每个像素,该图像显示现在的例程是正确的。黑色是例程确定该像素接近 120 个点之一的位置。 enter image description here

编辑:更快的处理
有许多 Math.* 函数正在执行。虽然我没有计时,但我认为这必须快得多。
1) 120个点的x,y坐标存储在数组中。
2) 使用矢量处理代替获取极坐标 mr、mt、pr 和 pt。

这里是 arcd 的推导,即使用向量的弧距离。

sint = sin(theta) = (M cross P)/mr/pr (cross product Mouse X Point)  
cost = cos(theta) = (M dot P)/mr/pr (dot product Mouse . Point)  
sint will be used to get arc distance, but sint goes to zero at theta=+-pi as well as theta=0, so:
mdotp will be used to determine if theta is near zero and not +-pi
arcd = pr*theta
arcd = pr*sin(theta) (good approximation for small theta)  
arcd = pr*abs(M cross P)/mr/mp (from above)
if ardd < del, check if mdotp > 0.

这里是 load-xy-arrays 以及新的检查器和检查例程。

  apx=[], apy=[]; // the saved x,y of the 120 points 
function loadapxapy() { // load arrays of px, py
  var itheta, theta
  for (var pr=1; pr<=5; pr+=1) { // 2-dimension arrays
    apx[pr] = []; apy[pr] = []; // 5 arrays, 1 for each pr
    for (itheta=0; itheta<24; itheta+=1) { // 24 x's and y's
      theta = Math.PI*itheta/12; 
      apx[pr][itheta] = pr*Math.cos(theta); 
      apy[pr][itheta] = pr*Math.sin(theta);
    }
  }
}
function checkr() { // check radial distance
  var mr = Math.sqrt(mx*mx+my*my); // mouse r
  for (var pr=1; pr<=5; pr+=1) { // check 1 to 5
   if (Math.abs(mr-pr) < del) { // mouser - pointr
      checkt(mr, pr); // if close, check thetas
    }
  }
}  
function checkt(mr, pr) { // check thetas
  var px, py, sint, mdotp, arcd;
  for (var itheta=0; itheta<24; itheta+=1) { // check 24
    px = apx[pr][itheta]; // get saved x
    py = apy[pr][itheta]; // and y
    // This arcd is derived from vector processing 
    // At least this doesn't use the accursed "atan"!
    sint = Math.abs(mx*py-my*px)/mr/pr; // sine
    arcd = pr*sint; // arc distance
    if (arcd<del) { // arc distance check
      mdotp = (mx*px+my*py); // final check
      if (mdotp > 0) { // to see if theta is near zero and not +-pi
        setpixelxy([mx, my]); // or whatever..
      }
    }
  }
}

关于javascript - 如何有效地检查鼠标是否位于 HTML5 Canvas 中的许多(120)个不同区域?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50827617/

相关文章:

javascript - arbor.js 自定义每个节点的形状

javascript - jQuery - 无法将类添加到具有 onClick 事件的按钮

javascript - 如何在键盘上按Enter键时调用JQUERY click()方法?

java - 在子菜单上实现 onClick 以开始新 Activity

javascript - 调整大小时 Canvas 引用丢失

javascript - 将 PictureStream 转换为 HTML5 canvas

javascript - 在移动设备上跳过加载 div 内容

javascript - 防止下拉 ul 在淡出时重新出现在 mouseenter 上

javascript - 使用 jQuery/Javascript 发射子弹

javascript - 底部工作表中的 Bootstrap 模态