2010-02-01 18 views
22

Los navegadores que han implementado partes de la especificación SVG (Firefox, etc.) hacen pruebas de impacto para nosotros de forma gratuita. Si conecto un oyente mousedown en un objeto SVG, me notifican cada vez que se hace clic en la forma. Esto es sorprendente, especialmente para formas poligonales complejas.Hit-testing formas SVG?

Me pregunto si hay alguna manera de que pueda utilizar esta característica para probar un poco más. Quiero saber si un rectángulo dado cruza cualquiera de mis formas SVG.

Por ejemplo, agrego 3 polígonos complejos a mi elemento. Ahora quiero saber si el rectángulo (40, 40, 100, 100) se cruza con alguno de ellos. ¿Alguien tiene una idea de cómo podría engancharme al soporte de pruebas de golpes ya disponible, en lugar de agregar todo este código yo mismo?

Gracias

Respuesta

13

no sé de ninguna manera de intersección de todo un rectángulo. Pero se puede intersectar un punto, por lo que se podría construir una comprobación más complicada de lo siguiente:

var el= document.elementFromPoint(x, y); 

le dará el elemento más alto apilados en una página-relación de coordenadas particular. Obtendrá el elemento <svg> si no se golpean formas dentro del SVG.

Esto no es un estándar Mozilla extension, pero también funciona en WebKit. Lamentablemente, aunque existe en Opera, no se verá dentro de <svg>, por lo que en ese navegador el elemento siempre será el SVGSVGElement.

+2

Gracias por señalar que su solución no era estándar en ese momento. Todavía es un borrador de trabajo, pero afortunadamente este método lo ha convertido en el (muy útil) especificación de CSSOM: http://dev.w3.org/csswg/cssom-view/#dom-document-elementfrompoint – natevw

+0

muchas muchas gracias por esto ... – Sudarshan

+0

Las coordenadas utilizadas en elementFromPoint() son absolutas, por lo tanto, a menos que su SVG comience en 0,0, deberá ajustar las coordenadas absolutas y relativas –

21

El SVG 1.1 DOM tiene simplemente el método adecuado (por desgracia aún no se ha implementado en Mozilla):

var nodelist = svgroot.getIntersectionList(hitrect, null); 

Para un ejemplo de trabajo completa ver here.

+0

¡genial! Entonces entre nosotros tenemos todos los navegadores principales. Bueno, excepto * ese *, obviamente ... – bobince

+0

Ok, así que solo tenemos que esperar a que esto se implemente en webkit, luego de eso, Safari y Chrome deben liberar una nueva versión creada en base a estos cambios. – user246114

+1

La publicación del blog se ha ido. –

0

getIntersectionList funciona bien en Opera. Mi problema es que las funciones en la especificación completa de SVG 1.1 con respecto a esto requieren que los elementos se deban representar (y posible objetivo para los eventos de puntero) para que se puedan detectar como aciertos. Desafortunadamente, esto hace que estas funciones sean inútiles para las pruebas de golpes en un mundo de juego donde solo una parte del mundo está actualmente visible.

+2

'opacity: 0' o' visibility: hidden' todavía significa que los elementos en cuestión se representan según svg, pero los elementos serán invisibles. Debería poder modificar '' pointer-events' para aplicarlo correctamente a estos elementos invisibles. –

0

La versión de Chrome de checkIntersection (y getIntersectionList) prueba los cuadros delimitadores de elementos, en lugar de los elementos mismos. Pude escribir mi propia CheckIntersection que funciona en Chrome utilizando un lienzo con este enfoque bastante complicado que parece funcionar bien para rectángulos pequeños y será lento para grandes, por lo que es bueno para la prueba de golpes. Esta técnica funcionará como un polyfill para checkIntersection en Chrome, para rectángulos pequeños y posiblemente otros navegadores que tengan implementaciones rotas de checkIntersection.

  1. crear una imagen que utiliza una URI de datos que contiene outerHTML de su SVG (puede que tenga que incluir reglas de estilo en ella también), como so (esta imagen no tiene por qué ser en la página). Puede usar un controlador de eventos onload para determinar cuándo se carga si es necesario.
  2. Crear un lienzo a utilizar para su rectángulo prueba de posicionamiento (este lienzo no tiene por qué estar en la página)

Para probar si un rectángulo cruza con cualquiera de sus formas, hacer esto:

  1. Asegúrese de que el lienzo es del mismo tamaño que el rectángulo (establecer su anchura y altura)
  2. Borrar el lienzo con el contexto de la lona clearRect() método
  3. Dibujar el SVG en el lienzo en -x, -y por lo que la porción de la imagen que se superpone al lienzo corresponde al área que desea probar usando drawImage()
  4. Obtenga el ImageData del lienzo usando el contexto getImageData(). Cada cuarto elemento de la matriz de datos es el byte alfa y un valor distinto de cero significa que parte de tu SVG se solapa con el rectángulo. Si todos los 4tos bytes son 0, entonces su SVG no se cruzó con el rectángulo.