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

Immaginiamo che circle.png sia un'immagine di sfondo trasparente di 400x400 pixel con un cerchio nel mezzo.Mappa immagine per canale alfa

Quello che ho ora è che l'intera area dell'immagine (400x400px) è cliccabile. Quello che mi piacerebbe avere è che solo il cerchio (pixel non trasparenti) sono cliccabili.

Naturalmente so che in questo esempio potrei usare il tag <map> e un'area circolare, ma sto cercando una soluzione generale che prenda in considerazione l'effettiva trasparenza dell'immagine e funzioni per qualsiasi tipo di immagini (es. forme regolari).

Il modo più complesso che ho potuto vedere è tracciare il contorno dell'immagine basandosi su ogni pixel alfa, convertirlo in un percorso (magari semplificarlo) e applicarlo come una mappa.

Esiste un modo più efficiente/diretto per farlo?

+0

Avete bisogno per fare questo perché le immagini saranno generate dinamicamente? Mentre sono sicuro che potrebbe essere fatto in javascript, probabilmente sarà lento. Avendo usato la "bacchetta magica" e quant'altro in Photoshop, non è banale nemmeno "fare le cose bene". Sembra che se generi immagini in modo dinamico, usa i dati di origine per creare una mappa di immagini. Se non lo sei, allora perché non farlo offline e usa una mappa di immagini? –

+0

Sì, sarà dinamico perché anche le immagini saranno caricate dinamicamente ... – lviggiani

risposta

17

Utilizzando il tag canvas, è possibile determinare il valore del colore di un pixel in un determinato punto. È possibile utilizzare i dati dell'evento per determinare le coordinate, quindi verificare la trasparenza. Tutto ciò che rimane è caricare l'immagine in una tela.

In primo luogo, ci prenderemo cura di che:

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

Questo primo bit afferra l'elemento canvas, quindi crea un oggetto Image. Quando l'immagine viene caricata, viene disegnata sulla tela. Abbastanza diretto! Tranne che ... se l'immagine non si trova nello stesso dominio del codice, sei contro la sicurezza dei criteri dello stesso dominio. Per ottenere i dati della nostra immagine, avremo bisogno che l'immagine sia ospitata localmente. Puoi anche codificare in base64 l'immagine, che va oltre lo scopo di questa risposta. (vedi this url per uno strumento per farlo).

Successivamente, collega l'evento click all'area di disegno. Quando quel clic entra, controlleremo per la trasparenza e agiamo solo per le regioni click non trasparenti:

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

La magia avviene nella funzione isTransparentUnderMouse, che ha bisogno di due argomenti: l'elemento canvas di destinazione (nel this click handler's scope) e i dati dell'evento (e, in questo esempio). Ora veniamo alla 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; 
}; 

In primo luogo, facciamo un po 'di danza intorno per ottenere la posizione precisa dell'elemento in questione. Useremo queste informazioni per passare all'elemento canvas. Lo getImageData ci fornirà, tra le altre cose, un oggetto data che contiene il RGBA della posizione che abbiamo specificato.

Se tutti questi valori sono 0, allora guardiamo alla trasparenza. In caso contrario, c'è un po 'di colore presente. -edit- come indicato nei commenti, l'unico valore che dobbiamo veramente considerare è l'ultimo, imgdata[3] nell'esempio precedente. I valori sono r (0) g (1) b (2) a (3) e la trasparenza è determinata da a, alpha. Puoi utilizzare questo stesso approccio per trovare qualsiasi colore con qualsiasi opacità che conosci per i dati rgba.

Provalo qui: http://jsfiddle.net/pJ3MD/1/

(nota: nel mio esempio, ho usato un'immagine base64 codificata per la protezione del dominio che ho citato È possibile ignorare che parte del codice, a meno che non si intende anche. sull'utilizzo di codifica Base64)

lo stesso esempio, con le modifiche al cursore del mouse gettato in per divertimento: http://jsfiddle.net/pJ3MD/2/

Documentazione

+0

+1 per lo sforzo che hai inserito in questa risposta. Anche +1 perché è una buona risposta! – Bojangles

+0

è una grande idea! grazie molto! – lviggiani

+0

solo un miglioramento estetico per isTransparentUnderMouse: ritorno (imgdata [0] + imgdata [1] + imgdata [2] + imgdata [3] == 0) – lviggiani

4

È possibile farlo utilizzando canvas HTML5. Disegna l'immagine sull'area di lavoro, collega un gestore di clic all'area di disegno e, nel gestore, controlla se il pixel su cui è stato fatto clic è trasparente.

+1

Ah, abbiamo pensato allo stesso modo, non ho visto la tua risposta perché ci è voluto un minuto per risolvere tutto! Saluti! –

1

grazie chris per questa grande risposta

ho aggiunto un paio di righe al codice per gestire con il ridimensionamento della tela

così quello che faccio ora è la creazione di una tela del esatto dimensione del pixel che l'immagine ha disegnato su di essa. come (per un'immagine 220px * 120px):

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

e scalare la tela usando i CSS:

#mainMenu_item{ width:110px; }

e la funzione isTransparentUnderMouse regolato assomiglia:

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