Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Image map by alpha channel

<img src="circle.png" onclick="alert('clicked')"/>

Let's imagine that circle.png is a 400x400 px transparent background image with a circle in the middle.

What I've got now is that the entire image area (400x400px) is clickable. What I would like the have is that only the circle (non transparent pixels) are clickable.

Of course I know that in this example I could use the <map> tag and a circular area, but I'm looking for a general solution which will take into consideration actual image transparency and work for any kind of images (i.e. non regular shapes).

The most complex way I could see is to trace the contour of the image basing on each pixel alpha, convert to a path (maybe simplify) and apply as a map.

Is there a more efficient / straightforward way to do so?

like image 933
lviggiani Avatar asked Jun 27 '12 14:06

lviggiani


2 Answers

Using the canvas tag, you can determine the color value of a pixel under a given spot. You can use the event data to determine the coordinates, then check for transparency. All that remains is loading the image up into a canvas.

First, we'll take care of that:

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

This first bit grabs the canvas element, then creates an Image object. When the image loads, it is drawn on the canvas. Pretty straightforward! Except... if the image is not on the same domain as the code, you're up against the same-domain policy security. In order to get the data of our image, we'll need the image to be locally hosted. You can also base64 encode your image, which is beyond the scope of this answer. (see this url for a tool to do so).

Next, attach your click event to the canvas. When that click comes in, we'll check for transparency and act only for non-transparent click regions:

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

The magic happens in the function isTransparentUnderMouse, which needs two arguments: the target canvas element (this in the click handler's scope) and the event data (e, in this example). Now we come to the meat:

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

First, we do some dancing around to get the precise position of the element in question. We're going to use that information to pass to the canvas element. The getImageData will give us, among other things, a data object that contains the RGBA of the location we specified.

If all those values are 0, then we're looking at transparency. If not, there's some color present. -edit- as noted in the comments, the only value we really need to look at is the last, imgdata[3] in the above example. The values are r(0)g(1)b(2)a(3), and transparency is determined by the a, alpha. You could use this same approach to find any color at any opacity that you know the rgba data for.

Try it out here: http://jsfiddle.net/pJ3MD/1/

(note: in my example, I used a base64 encoded image because of the domain security I mentioned. You can ignore that portion of the code, unless you also intend on using base64 encoding)

Same example, with changes to the mouse cursor thrown in for fun: http://jsfiddle.net/pJ3MD/2/

Documentation

  • Image object on MDN - https://developer.mozilla.org/en/DOM/Image
  • Tutorial for using images with canvas on MDN - https://developer.mozilla.org/en/Canvas_tutorial/Using_images
  • Canvas portal on MDN - https://developer.mozilla.org/en/HTML/Canvas
  • HTML canvas element on MDN (getContext) - https://developer.mozilla.org/en/DOM/HTMLCanvasElement/
  • CanvasRenderingContext2D on MDN (getImageData) - https://developer.mozilla.org/en/DOM/CanvasRenderingContext2D
  • Pixel manipulation on MDN - https://developer.mozilla.org/En/HTML/Canvas/Pixel_manipulation_with_canvas/
like image 149
Chris Baker Avatar answered Oct 05 '22 06:10

Chris Baker


You can do this using HTML5 canvas. Draw the image in to the canvas, attach a click handler to the canvas, and in the handler, check if the pixel that was clicked on is transparent.

like image 25
akonsu Avatar answered Oct 05 '22 04:10

akonsu