2011-09-06 8 views
8

Potrzebujesz pomocy tutaj. Jestem projektantem interfejsu użytkownika, który nie jest dobry w liczbach i tworzy eksperymentalny formularz internetowy i muszę wiedzieć, który element wejściowy jest najbliżej klikniętego punktu na stronie internetowej. Wiem, jak zrobić sąsiad z punktami, ale elementy wejściowe to prostokąty, a nie punkty, więc utknąłem.Znajdowanie elementu najbliżej klikniętego punktu

Używam jQuery. Potrzebuję pomocy w tym małym algo. Kiedy skończę eksperyment, pokażę wam, co robię.

UPDATE

myślałem o tym, jak to działa. Spojrzeć na tym rysunku:

Nearest

każdego prostokąta ma 8 punktów (raczej 4 punktów i 4 linii), które mają istotne znaczenie. Tylko wartość x jest znacząca dla punktów poziomych (czerwona kropka) i tylko wartość y jest znacząca dla punktów pionowych (zielona kropka). Zarówno x, jak i y są znaczące dla rogów.

Pomarańczowe krzyże są punktami, od których należy mierzyć - kliknięcia myszą w moim przypadku użycia. Jasnopurpurowe linie to odległości między pomarańczowym krzyżem i możliwym najbliższym punktem.

Więc ... dla każdego pomarańczowego krzyża, przechodź przez każdy z 8 punktów n każdego prostokąta, aby znaleźć najbliższą krawędź lub róg najbliższy każdego prostokąta do pomarańczowego krzyża. Prostokąt o najniższej wartości jest najbliższy.

Potrafię konceptualizować i wizualizować to, ale nie mogę umieścić go w kodzie. Wsparcie!

+0

pomocą 4 punktów, które reprezentują prostokąt w swoim algorytm najbliższego sąsiada. Lub użyj środkowego punktu prostokąta cx = (lewa + szerokość)/2, cy = (góra + wysokość)/2. –

+0

jest szansa, że ​​możesz napisać jakiś kod lub coś zrobić w jsfiddle.net? to wszystko jest trochę hipotetyczne, inaczej ... – T9b

+0

Dodano ilustrację wyjaśniającą problem i sposób jego rozwiązania. –

Odpowiedz

3

Twój algorytm jest poprawny. Ponieważ potrzebujesz pomocy w kodzie, a nie w algorytmie, oto kod:

To może nie być najbardziej efektywne. Ale działa.

// Define the click 
var click = Array(-1, -2); // coodinates in x,y 

// Define the buttons 
// Assuming buttons do not overlap 
var button0 = Array(
    Array(0, 0), // bottom-left point (assuming x is horizontal and y is vertical) 
    Array(6, 6) // upper-right point 
); 

var button1 = Array(
    Array(10, 11), 
    Array(17, 15) 
); 

var button2 = Array(
    Array(-8, -5), 
    Array(-3, -1) 
); 

// Which button to trigger for a click 
i = which(click, Array(button0, button1, button2)); 
alert(i); 


function which(click, buttons){ 
    // Check if click is inside any of the buttons 
    for (i in buttons){ 
     var button = buttons[i]; 
     var bl = button[0]; 
     var tr = button[1]; 

     if ((click[0] >= bl[0] && click[0] <= tr[0]) && 
      (click[1] >= bl[1] && click[1] <= tr[1])){ 
      return i; 
     } 
    } 

    // Now calculate distances 
    var distances = Array(); 

    for (i in buttons){ 
     var button = buttons[i]; 
     var bl = button[0]; 
     var tr = button[1]; 

     if ((click[0] >= bl[0] && click[0] <= tr[0])) { 
      distances[i] = Math.min(Math.abs(click[1]-bl[1]), Math.abs(click[1]-tr[1])); 
     } 
     else if ((click[1] >= bl[1] && click[1] <= tr[1])) { 
      distances[i] = Math.min(Math.abs(click[0]-bl[0]), Math.abs(click[0]-tr[0])); 
     } 
     else{ 
      distances[i] = Math.sqrt(
           (Math.pow(Math.min(Math.abs(click[0]-bl[0]), Math.abs(click[0]-tr[0])), 2)) + 
           (Math.pow(Math.min(Math.abs(click[1]-bl[1]), Math.abs(click[1]-tr[1])), 2)) 
          ); 
     } 
    } 

    var min_id = 0; 
    for (j in distances){ 
     if (distances[j] < distances[min_id]){ 
      min_id = j; 
     } 
    } 

    return min_id; 
} 
+0

Świetnie. Właśnie to czego potrzebuje. Jak sprawić, by kod mógł się dostosować do dowolnej szerokości i wysokości? –

+1

Można dostosować do dowolnej szerokości i wysokości. Musisz tylko zdefiniować wymiary przycisków i współrzędne kliknięcia w górnej części kodu JavaScript. – uzyn

+0

Fajne dzięki człowieku. –

2

Możesz odszukać najbliższy punkt narożny wszystkich prostokątów. Działa to w większości przypadków, jest szybkie i łatwe do wdrożenia. Dopóki twoje prostokąty są wyrównane na regularnej siatce, ta metoda daje ci najbliższy prostokąt.

0

Sposób, w jaki to zrobię, nie jest zgodny z liczbami, ale z logiką.

Jestem zakładając, że chcesz skończyć z czymś, co mówi: „Jeśli x jest najbliższy elementem wtedy coś zrobić po kliknięciu gdzie indziej wtedy coś zrobić, aby x”

Mogłeś to zrobić, jeśli każdy z elementy, z którymi chcesz coś zrobić, były w prostszych pojemnikach, które były większe niż element, który chcesz traktować, ale nie większy niż w połowie między obiektem, który zawiera, a jego najbliższym najbliższym obiektem. Siatka w rzeczywistości.

podaj wszystkie pojemniki tej samej klasy.

Następnie można powiedzieć: "jeśli kliknięto y, przejdź do x", to już wiesz, który element znajduje się w każdym pojemniku.

bym napisać kod, ale wyjeżdżam pracy ...

+0

Nie chcę dodatkowych znaczników. –

0

Jeśli chcesz dowiedzieć się odległość między dwoma punktami na siatce 2D, można użyć następującego wzoru:

(punkty 2D & B)

distanceX = Ax - Bx

distanceY = Ay - B.y

ogólnyDystans = SquareRoot ((distX * distX) + (distY * distY))

Kiedy można sprawdzić odległość między dwoma punktami można dość łatwo zorientować się, które rogu prostokąta Twój kliknięcie myszą jest najbliżej zbyt. Jest wiele rzeczy, które możesz zrobić, aby zoptymalizować zamierzony algorytm, ale powinno to dać ci dobry początek.

0

lol, pytanie brzmi, dlaczego myślisz o kształtach? Twoje pytanie naprawdę brzmi: "jeśli kliknę współrzędne, znajdź mi najbliższy węzeł/punkt do mojego kliknięcia", co jest kwestią przechodzenia przez różne węzły i obliczania odległości.

Jeśli samo X, wykorzystanie różnicy y

Jeśli sama y, x stosowanie różnica

inaczej używać hypotheneuse

Po znalezieniu najbliższego punktu można uzyskać odpowiedni kształt rodzicem? To zadziała, ponieważ próbujesz przyciągnąć do najbliższego punktu. Więc będzie działać nawet z fantazyjnymi kształtami, takimi jak gwiazdy.

2

Dodanie stosunkowo nowym elementFromPoint() API pozwala nam podjąć alternatywną, potencjalnie lżejszego podejścia: możemy trafić testu wokół kursora myszy, przechodząc w większych kręgach aż znajdziemy najbliższy element.

Przygotowałem tutaj szybki, nieprodukcyjny przykład: http://jsfiddle.net/yRhhs/ (Chrome/Safari tylko z powodu użycia webkitMatchesSelector). Wydajność może być opóźniona z powodu kropek używanych do wizualizacji algorytmu.

Rdzeń kodu, poza lekkimi optymalizacji wydajności i wiązania zdarzeń, jest to nieco:

function hitTest(x, y){ 
    var element, i = 0; 
    while (!element){ 
     i = i + 7; // Or some other threshold. 

     if (i > 250){ // We do want some safety belts on our while loop. 
      break; 
     } 

     var increment = i/Math.sqrt(2); 
     var points = [ 
      [x-increment, y-increment], [x+increment, y-increment], 
      [x+increment, y+increment], [x-increment, y+increment] 
     ]; 

     // Pop additional points onto the stack as the value of i gets larger. 
     // ... 

     // Perhaps prematurely optimized: we're using Array.prototype.some to bail-out 
     // early once we've found a valid hit target. 
     points.some(function(coordinates){ 
      var hit = document.elementFromPoint.apply(document, coordinates); 
      // isValidHit() could simply be a method that sees whether the current 
      // element matches the kinds of elements we'd like to see. 
      if (isValidHit(hit)){ 
       element = hit; 
       return true; 
      } 
     }); 
} 
Powiązane problemy