2011-09-06 17 views
8

Hai bisogno di aiuto qui. Sono un progettista di interfacce utente che non è bravo in numeri che fanno un design di modulo web sperimentale e ho bisogno di sapere quale elemento di input è più vicino a un punto cliccato su una pagina web. So come fare il vicino più vicino con i punti, ma gli elementi di input sono rettangoli e non punti, quindi sono bloccato.Trovare l'elemento più vicino al punto cliccato

Sto usando jQuery. Ho solo bisogno di aiuto con questo piccolo algo. Una volta che ho finito il mio esperimento, ti mostrerò cosa sto facendo.

UPDATE

ho pensato a come si può lavorare. Guardare a questo schema:

Nearest

Ogni rettangolo ha 8 punti (o meglio 4 punti e 4 linee) che sono significativi. Solo il valore x è significativo per i punti orizzontali (punto rosso) e solo il valore y è significativo per i punti verticali (punto verde). Sia x che y sono significativi per gli angoli.

Le croci arancioni sono i punti da misurare contro: clic del mouse nel mio caso d'uso. Le linee viola chiaro sono le distanze tra la croce arancione e il punto più vicino possibile.

Quindi ... per una data croce arancione, passare attraverso ciascuno degli 8 punti su ogni rettangolo per trovare il bordo o l'angolo più vicino di ogni rettangolo alla croce arancione. Il rettangolo con il valore più basso è quello più vicino.

Posso concettualizzarlo e visualizzarlo ma non posso inserirlo nel codice. Aiuto!

+0

Utilizzare i 4 punti che rappresentano un rettangolo nel vostro algoritmo vicino più prossimo. Oppure usa il punto centrale del rettangolo cx = (sinistra + larghezza)/2, cy = (sopra + altezza)/2. –

+0

c'è qualche possibilità che tu possa postare del codice o fare qualcosa in jsfiddle.net? è tutto un po 'ipotetico altrimenti ... – T9b

+0

Aggiunta un'illustrazione per spiegare il problema e come potrebbe essere risolto. –

risposta

3

L'algoritmo è corretto. Poiché hai bisogno di aiuto nel codice e non nell'algoritmo, ecco il codice:

Potrebbe non essere il più efficiente. Ma funziona.

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

Grande. Proprio quello di cui ho bisogno. Come renderei il codice adattabile a qualsiasi larghezza e altezza? –

+1

È adattabile a qualsiasi larghezza e altezza. Dovrai solo definire le dimensioni dei pulsanti e le coordinate del clic nella parte superiore del codice JavaScript. – uzyn

+0

Cool grazie amico. –

2

È possibile cercare il punto d'angolo più vicino di tutti i rettangoli. Questo funziona nella maggior parte dei casi, è veloce e facile da implementare. Finché i rettangoli sono allineati su una griglia regolare questo metodo ti dà il rettangolo più vicino.

0

Il modo in cui lo farei non è con i numeri, ma con la logica.

sto supponendo che si vuole finire con qualcosa che dice: "se x è l'elemento più vicino poi fare qualcosa quando ho cliccato altrove quindi fare qualcosa per x"

Si potrebbe fare questo se ognuno di gli elementi con cui vuoi fare qualcosa erano in semplici contenitori <div> più grandi dell'elemento che vuoi trattare, ma non più grandi di metà strada tra l'oggetto che contiene e il prossimo oggetto più vicino. Una griglia in effetti.

dare tutti i contenitori della stessa classe.

Quindi si potrebbe dire "se si fa clic su go go do something to x", si saprebbe già quale elemento si trova in ciascun contenitore.

che avrei scritto il codice, ma sto partendo lavoro ...

+0

Non voglio markup extra. –

0

Se si vuole trovare la distanza tra due punti su una griglia 2D, è possibile utilizzare la seguente formula:

(per i punti 2D Un & B)

distanceX = Ax - Bx

distanceY = Ay - B.y

totalDistance = squareRoot ((distx * distx) + (Disty * Disty))

Una volta che è possibile controllare la distanza tra due punti è possibile abbastanza facilmente capire quale angolo rettangolo il click del mouse è più vicino troppo. Ci sono molte cose che puoi fare per ottimizzare il tuo algoritmo, ma questo dovrebbe darti un buon inizio.

0

lol, la domanda è: perché stai pensando alle forme? la tua domanda è davvero "se faccio clic su una coordinata, trovami il nodo/punto più vicino al mio clic", che è una questione di passare attraverso i vari nodi e calcolare le distanze.

Se stesso X, l'uso differenza y

Se stesso y, uso x differenza

altrimenti utilizzare hypotheneuse

Una volta trovato il punto più vicino è possibile ottenere la giusta forma genitore? Funzionerà perché stai provando a scattare al punto più vicino. Quindi funzionerà anche con forme fantasiose come le stelle.

2

L'aggiunta del relativamente nuovo elementFromPoint() API ci permette di dare un'alternativa, potenzialmente approccio più leggero: siamo in grado di colpire di prova attorno al cursore del mouse, andando in cerchi più grandi fino a trovare l'elemento più vicino.

Ho creato un esempio rapido non di produzione: http://jsfiddle.net/yRhhs/ (Chrome/Safari solo per l'utilizzo di webkitMatchesSelector). Le prestazioni possono essere rallentate a causa dei punti utilizzati nella visualizzazione dell'algoritmo.

Il nucleo del codice, al di fuori delle ottimizzazioni delle prestazioni leggeri e binding di eventi, è questo bit:

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; 
      } 
     }); 
} 
Problemi correlati