2012-06-27 16 views
6
<img src="circle.png" onclick="alert('clicked')"/> 

Imaginemos que circle.png es una imagen de fondo transparente de 400x400 px con un círculo en el medio.Mapa de imagen por canal alfa

Lo que tengo ahora es que se puede hacer clic en el área de la imagen completa (400x400px). Lo que me gustaría tener es que solo se puede hacer clic en el círculo (píxeles no transparentes).

Por supuesto sé que en este ejemplo que podría utilizar la etiqueta <map> y un área circular, pero yo estoy buscando una solución general que tendrá en cuenta la transparencia de imagen real y trabajar para cualquier tipo de imágenes (es decir, no formas regulares).

La forma más compleja que pude ver es trazar el contorno de la base de la imagen en cada píxel alfa, convertirla en una ruta (tal vez simplificar) y aplicarla como un mapa.

¿Existe alguna manera más eficiente/directa de hacerlo?

+0

¿Necesita hacer esto porque las imágenes se generarán dinámicamente? Aunque estoy seguro de que podría hacerse en JavaScript, probablemente sea lento. Después de haber usado la "varita mágica" y otras cosas en Photoshop, tampoco es trivial "hacerlo bien". Parece que si está generando imágenes dinámicamente, use los datos de origen para crear un mapa de imágenes. Si no lo eres, ¿por qué no hacerlo sin conexión y usar un mapa de imagen? –

+0

Sí, eso va a ser dinámico, ya que las imágenes también se cargarán dinámicamente ... – lviggiani

Respuesta

17

Con la etiqueta canvas, puede determinar el valor de color de un píxel en un punto determinado. Puede usar los datos del evento para determinar las coordenadas, luego verifique la transparencia. Todo lo que queda es cargar la imagen en un lienzo.

En primer lugar, nos ocuparemos de que:

var ctx = document.getElementById('canvas').getContext('2d'); 
    var img = new Image(); 
    img.onload = function(){ 
    ctx.drawImage(img,0,0); 
    }; 
    img.src = [YOUR_URL_HERE]; 

Este primer bit agarra el elemento canvas, a continuación, crea un objeto Image. Cuando la imagen se carga, se dibuja en el lienzo. ¡Muy claro! Excepto ... si la imagen no está en el mismo dominio que el código, te enfrentas a la seguridad de política del mismo dominio. Para obtener los datos de nuestra imagen, necesitaremos que la imagen se aloje localmente. También puede base64 codificar su imagen, que está más allá del alcance de esta respuesta. (ver this url para que una herramienta lo haga).

A continuación, adjunte su evento de clic al lienzo. Cuando esto viene en clic, comprobaremos la transparencia y actuar sólo a ciertas regiones clic no transparentes:

if (isTransparentUnderMouse(this, e)) 
     return; 
    // do whatever you need to do 
    alert('will do something!'); 

La magia sucede en la función isTransparentUnderMouse, que necesita dos argumentos: el elemento canvas de destino (en el this haga clic en el alcance del manejador) y los datos del evento (e, en este ejemplo). Ahora llegamos a la carne:

var isTransparentUnderMouse = function (target, evnt) { 
    var l = 0, t = 0; 
    if (target.offsetParent) { 
     var ele = target; 
     do { 
      l += ele.offsetLeft; 
      t += ele.offsetTop; 
     } while (ele = ele.offsetParent); 
    } 
    var x = evnt.page.x - l; 
    var y = evnt.page.y - t; 
    var imgdata = target.getContext('2d').getImageData(x, y, 1, 1).data; 
    if (
     imgdata[0] == 0 && 
     imgdata[1] == 0 && 
     imgdata[2] == 0 && 
     imgdata[3] == 0 
    ){ 
     return true; 
    } 
    return false; 
}; 

En primer lugar, hacemos un poco de baile en torno a obtener la posición exacta del elemento en cuestión. Vamos a usar esa información para pasar al elemento canvas. El getImageData nos dará, entre otras cosas, un objeto data que contiene el RGBA de la ubicación que hemos especificado.

Si todos esos valores son 0, entonces estamos viendo la transparencia. Si no, hay un poco de color presente. -edit- como se menciona en los comentarios, el único valor que realmente necesitamos ver es el último, imgdata[3] en el ejemplo anterior. Los valores son r (0) g (1) b (2) a (3) y la transparencia está determinada por a, alfa. Puede usar este mismo enfoque para encontrar cualquier color con cualquier opacidad para la que conozca los datos de rgba.

Pruébalo aquí: http://jsfiddle.net/pJ3MD/1/

(nota: en mi ejemplo, he usado una imagen codificada en base64 debido a la seguridad del dominio que he mencionado Puede pasar por alto esa parte del código, a menos que también tiene la intención. sobre el uso de la codificación base64)

mismo ejemplo, con cambios en el cursor del ratón tirado en una diversión: http://jsfiddle.net/pJ3MD/2/

Documentación

+0

+1 por el esfuerzo que ha puesto en esta respuesta. ¡También +1 porque es una buena respuesta! – Bojangles

+0

¡esa es una gran idea! ¡muchas gracias! – lviggiani

+0

solo una mejora cosmética para isTransparentUnderMouse: return (imgdata [0] + imgdata [1] + imgdata [2] + imgdata [3] == 0) – lviggiani

4

Puede hacerlo utilizando un lienzo HTML5. Dibuje la imagen en el lienzo, coloque un manejador de clics en el lienzo y, en el controlador, compruebe si el píxel en el que se hizo clic es transparente.

+1

¡Ah, pensamos igual en esta, no vi su respuesta porque tardó un minuto en solucionarse todo! ¡Aclamaciones! –

1

gracias Chris por esta gran respuesta

añadí unas pocas líneas al código de manejar con la ampliación del lienzo

así que lo que ahora no es la creación de un lienzo de la exacta tamaño de píxel que tiene la imagen que se dibuja en él. similares (por una imagen 220px * 120px):

<canvas width="220" height="120" id="mainMenu_item"></canvas> 

y escalar el lienzo con CSS:

#mainMenu_item{ width:110px; }

y la función isTransparentUnderMouse ajustado se ve así:

var isTransparentUnderMouse = function (target, evnt) { 

    var l = 0, t = 0; 
    if (target.offsetParent) { 
     var ele = target; 
     do { 
      l += ele.offsetLeft; 
      t += ele.offsetTop; 
     } while (ele = ele.offsetParent); 
    } 

    var x = evnt.pageX - l; 
    var y = evnt.pageY - t; 

    var initialWidth = $(evnt.target).attr('width'); 
    var clientWidth = evnt.target.clientWidth; 
    x = x * (initialWidth/clientWidth); 

    var initialHeight = $(evnt.target).attr('height');; 
    var clientHeight = evnt.target.clientHeight; 
    y = y * (initialHeight/clientHeight); 

    var imgdata = target.getContext('2d').getImageData(x, y, 1, 1).data; 

    if (
     imgdata[0] == 0 && 
     imgdata[1] == 0 && 
     imgdata[2] == 0 && 
     imgdata[3] == 0 
    ){ 
     return true; 
    } 
    return false; 
}; 
Cuestiones relacionadas