Как эффективно проверить, находится ли мышь во многих (120) разных областях холста HTML5? - PullRequest
0 голосов
/ 13 июня 2018

У меня есть полярный график (см. Изображение) с 120 различными точками.Я хочу сделать так, чтобы, если пользователь щелкает или наводит курсор на одну из точек, отображается координата этой точки.У меня есть массив с именем pointCoordinates, в котором хранится каждая координата холста каждой точки, например:

[[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:

После использования кода, размещенного ниже, и рисования прямоугольника в «кликабельном» месте на карте, я получаю это изображение.Я не хочу, чтобы обнаружение щелчка было идеальным, но это довольно далеко после пи / 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 функция, которая вызывает checkrt.enter image description here

JSBIN Имейте в виду, ширина экрана должна быть больше высоты, чтобы это работало должным образом.

Изображение, сгенерированное mt-rt.Позже я сделал небольшое редактирование, чтобы весь круг покрывался, когда тета = 0.

enter image description here

1 Ответ

0 голосов
/ 13 июня 2018

РЕДАКТИРОВАТЬ: мой (принятый) ответ был плохим.Это исправляет это:

Предполагается, что r будет от 1 до 5. Преобразуйте мышь декартовой mx, my в полярную mr, mt.Сначала проверьте, близок ли г-н к 1 из 5 радиусов.Функция checkr делает это.Если он близок, то проверьте, близок ли m к 1 из 24 тэт.Функция checkt делает это.Сложность состоит в том, что функция atan2 не является непрерывной в pi радианах, где находятся точки, поэтому делайте разрыв в -pi / 24 радианах, где нет точек.

Значение "close" равно 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.ОП обнаружил мою ошибку, обработав каждый пиксель на холсте, и обнаружил, что возникла проблема.Я также обработал каждый пиксель, и это изображение показывает процедуры, чтобы быть правильными сейчас.Черный цвет - это место, где процедуры определяют, что пиксель близок к одной из 120 точек.enter image description here

РЕДАКТИРОВАТЬ: Ускоренная обработка
Выполняется много математических функций *.Хотя я ничего не рассчитывал, я думаю, что это должно быть намного быстрее.
1) Координаты x, y из 120 точек сохраняются в массивах.
2) Вместо того, чтобы получать полярные значения mr, mt, pr, и pt, используйте векторную обработку.

Здесь вывод дуги, расстояние дуги с использованием векторов.

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 и новые процедуры checkr и checkt.

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