Image map by alpha channel

浪尽此生 提交于 2019-12-18 03:43:42

问题


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


回答1:


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/



回答2:


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.




回答3:


thank you chris for this great answer

I added a few lines to the code to handle with scaling the canvas

so what I do now is creating a canvas of the exact pixel size the image has that is drawn on it. like (for an Image 220px*120px):

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

and scale the canvas using css:

#mainMenu_item{ width:110px; }

and the adjusted isTransparentUnderMouse function looks like:

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


来源:https://stackoverflow.com/questions/11228987/image-map-by-alpha-channel

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!