2011-09-06 17 views
8

Necesito ayuda aquí. Soy un diseñador de UI que no es bueno para los números que hacen un diseño de formulario web experimental y necesito saber qué elemento de entrada está más cerca de un punto en una página web. Sé cómo hacer el vecino más cercano con puntos, pero los elementos de entrada son rectángulos, no puntos, así que estoy atascado.Encontrar el elemento más cercano al punto al que se ha hecho clic

Estoy usando jQuery. Solo necesito ayuda con este pequeño algo. Una vez que termine con mi experimento, les mostraré lo que estoy haciendo.

ACTUALIZACIÓN

pensé en cómo se puede trabajar. Mira este diagrama:

Nearest

Cada rectángulo tiene 8 puntos (o más bien de 4 puntos y 4 líneas) que son significativos. Solo el valor x es significativo para puntos horizontales (punto rojo) y solo el valor y es significativo para puntos verticales (punto verde). Tanto x como y son importantes para las esquinas.

Las cruces naranjas son los puntos a medir en contra: clics del mouse en mi caso de uso. Las líneas moradas claras son las distancias entre la cruz naranja y el punto más cercano posible.

Así que ... para cualquier cruz naranja, recorra cada uno de los 8 puntos n de cada rectángulo para encontrar el borde más cercano o la esquina más cercana de cada rectángulo a la cruz naranja. El rectángulo con el valor más bajo es el más cercano.

Puedo conceptualizarlo y visualizarlo pero no puedo ponerlo en el código. ¡Ayuda!

+0

Utilice los 4 puntos que representan un rectángulo en el algoritmo del vecino más cercano. O use el punto central del rectángulo cx = (izquierda + ancho)/2, cy = (arriba + altura)/2. –

+0

¿hay alguna posibilidad de que puedas publicar algún código o hacer algo en jsfiddle.net? es todo un poco hipotético de lo contrario ... – T9b

+0

Se agregó una ilustración para explicar el problema y cómo se puede resolver. –

Respuesta

3

Su algoritmo es correcto. Como necesita ayuda en el código y no en el algoritmo, este es el código:

Puede que no sea el más eficiente. Pero funciona.

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

Genial. Justo lo que necesito. ¿Cómo haría el código adaptable a cualquier ancho y alto? –

+1

Es adaptable a cualquier ancho y alto. Simplemente deberá definir las dimensiones de los botones y las coordenadas del clic en la parte superior del JavaScript. – uzyn

+0

Cool thanks man. –

2

Puede buscar el punto de esquina más cercano de todos los rectángulos. Esto funciona en la mayoría de los casos, es rápido y fácil de implementar. Siempre que sus rectángulos estén alineados en una cuadrícula regular, este método le proporciona el rectángulo más cercano.

0

La forma en que lo haría no es con números, sino con lógica.

Asumo que desea terminar con algo que dice: "Si x es el elemento más cercano a continuación, haga algo cuando hice clic en otro lugar y luego hacer algo para x"

usted puede hacer esto si cada uno de los elementos con los que desea hacer algo estaban en contenedores simples <div> que eran más grandes que el elemento que desea tratar, pero no más grandes que la mitad entre el objeto que contiene y su próximo objeto más cercano. Una cuadrícula de hecho.

otorgue a todos los contenedores la misma clase.

Entonces se podría decir, "si se hace clic en y se va a hacer algo en x", ya se sabe qué elemento está en cada contenedor.

me gustaría escribir el código, pero estoy de salir del trabajo ...

+0

No quiero marcado adicional. –

0

Si usted quiere encontrar la distancia entre dos puntos en una cuadrícula 2D, puede utilizar la siguiente fórmula:

(para puntos 2D a & B)

distanceX = Ax - Bx

distanceY = Ay - B.Y

totalLa = squareRoot ((DISTX * DISTX) + (Disty * Disty))

Una vez que puede comprobar la distancia entre dos puntos puede calcular con bastante facilidad qué esquina del rectángulo el clic del ratón es más cercano también. Hay muchas cosas que puede hacer para optimizar su algoritmo previsto, pero esto debería darle un buen comienzo.

0

lol, la pregunta es ¿por qué estás pensando en formas? su pregunta es realmente "si hago clic en una coordenada, busque el nodo/punto más cercano a mi clic", que es cuestión de pasar por varios nodos y calcular distancias.

Si es la misma X, el uso y la diferencia

Si es la misma y, el uso de la diferencia x

utilizar de otro modo hypotheneuse

Una vez que encuentre el punto más cercano se puede obtener el derecho de forma original? Esto funcionará porque estás tratando de ajustar al punto más cercano. Así que incluso funcionará con formas elegantes como estrellas.

2

La adición de la relativamente nueva elementFromPoint() API permite a echar una alternativa, potencialmente enfoque más claro: podemos golpear a prueba alrededor del cursor del ratón, dando vueltas en círculos más grandes hasta que encontramos el elemento más cercano.

Puse juntos un ejemplo rápido, sin producción aquí: http://jsfiddle.net/yRhhs/ (Chrome/Safari solo debido al uso de webkitMatchesSelector). El rendimiento puede ser lento debido a los puntos utilizados en la visualización del algoritmo.

El núcleo del código, fuera de las optimizaciones de rendimiento de luz y enlaces de eventos, es este 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; 
      } 
     }); 
} 
Cuestiones relacionadas