Alpha通道的图像映射

lvi*_*ani 6 html javascript imagemap

<img src="circle.png" onclick="alert('clicked')"/>
Run Code Online (Sandbox Code Playgroud)

让我们假设circle.png是一个400x400像素的透明背景图像,中间有一个圆圈.

我现在得到的是整个图像区域(400x400px)是可点击的.我想要的是只有圆圈(非透明像素)是可点击的.

当然我知道在这个例子中我可以使用<map>标签和圆形区域,但我正在寻找一种通用的解决方案,它将考虑实际的图像透明度并适用于任何类型的图像(即非常规形状).

我能看到的最复杂的方法是根据每个像素alpha跟踪图像的轮廓,转换为路径(可能简化)并应用为地图.

有没有更有效/直接的方法呢?

Chr*_*ker 17

使用canvas标签,您可以确定给定点下像素的颜色值.您可以使用事件数据来确定坐标,然后检查透明度.剩下的就是将图像加载到画布中.

首先,我们会照顾到:

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

第一个位抓取canvas元素,然后创建一个Image对象.加载图像时,它将在画布上绘制.很简单!除了......如果图像与代码不在同一个域中,您就会遇到相同的域策略安全性.为了获取图像的数据,我们需要将图像本地托管.您还可以对图像进行base64编码,这超出了本答案的范围.(请参阅此URL以获取执行此操作的工具).

接下来,将您的单击事件附加到画布.当点击进入时,我们将检查透明度并仅针对非透明点击区域:

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

魔术发生在函数中isTransparentUnderMouse,它需要两个参数:目标画布元素(this在单击处理程序的作用域中)和事件数据(在本例中为e).现在我们来吃肉:

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;
};
Run Code Online (Sandbox Code Playgroud)

首先,我们做一些跳舞,以获得有问题的元素的精确位置.我们将使用该信息传递给canvas元素.该getImageData给我们,除其他事项外,一个data包含我们指定的位置的RGBA对象.

如果所有这些值都是0,那么我们正在考虑透明度.如果没有,会出现一些颜色.-edit-如评论中所述,imgdata[3]在上面的例子中,我们真正需要关注的唯一值是最后一个.值为r(0)g(1)b(2)a(3),透明度由a,α确定.您可以使用相同的方法在任何您知道rgba数据的不透明度中查找任何颜色.

在这里试试:http://jsfiddle.net/pJ3MD/1/

(注意:在我的示例中,由于我提到的域安全性,我使用了base64编码的图像.除非您还打算使用base64编码,否则可以忽略该部分代码)

同样的例子,为了好玩而改变鼠标光标:http://jsfiddle.net/pJ3MD/2/

文档