问题
<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