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

Hãy tưởng tượng rằng circle.png là hình nền trong suốt 400x400 px có hình tròn ở giữa.Bản đồ hình ảnh theo kênh alpha

Điều tôi hiện có là toàn bộ khu vực hình ảnh (400x400px) có thể nhấp được. Điều tôi muốn là chỉ có vòng tròn (các điểm ảnh không trong suốt) mới có thể nhấp được. Tất nhiên tôi biết rằng trong ví dụ này tôi có thể sử dụng thẻ <map> và một vùng tròn, nhưng tôi đang tìm một giải pháp tổng quát sẽ xem xét tính minh bạch của hình ảnh thực tế và làm việc cho bất kỳ loại hình ảnh nào (tức là không hình dạng thông thường).

Cách phức tạp nhất mà tôi có thể thấy là theo dõi đường bao của hình ảnh dựa trên từng pixel alpha, chuyển đổi thành đường dẫn (có thể đơn giản hóa) và áp dụng làm bản đồ.

Có cách nào hiệu quả hơn/đơn giản hơn để làm như vậy không?

+0

Bạn có cần để làm điều này bởi vì các hình ảnh sẽ được tạo động? Trong khi tôi chắc chắn nó có thể được thực hiện trong javascript, nó có thể sẽ được làm chậm. Sau khi sử dụng "cây đũa thần" và không có gì trong Photoshop, nó không tầm thường để "làm cho nó đúng". Có vẻ như nếu bạn đang tạo hình ảnh động, hãy sử dụng dữ liệu nguồn để tạo một imagemap. Nếu bạn không, thì tại sao không làm điều đó ngoại tuyến và sử dụng một imagemap? –

+0

Vâng, điều đó sẽ tự động vì ảnh sẽ được nạp tự động ... – lviggiani

Trả lời

17

Sử dụng thẻ canvas, bạn có thể xác định giá trị màu của pixel dưới một điểm nhất định. Bạn có thể sử dụng dữ liệu sự kiện để xác định tọa độ, sau đó kiểm tra độ trong suốt. Tất cả những gì còn lại là tải hình ảnh lên thành một khung hình.

Đầu tiên, chúng tôi sẽ chăm sóc cho rằng:

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

bit đầu tiên này lấy phần tử canvas, sau đó tạo ra một đối tượng Image. Khi hình ảnh tải, nó sẽ được vẽ trên canvas. Khá đơn giản! Ngoại trừ ... nếu hình ảnh không nằm trên cùng một tên miền với mã, bạn sẽ chống lại chính sách bảo mật của cùng một miền. Để có được dữ liệu hình ảnh của chúng tôi, chúng tôi sẽ cần hình ảnh được lưu trữ cục bộ. Bạn cũng có thể mã hóa base64 image của bạn, nằm ngoài phạm vi của câu trả lời này. (xem this url để có công cụ để thực hiện việc này).

Tiếp theo, đính kèm sự kiện nhấp của bạn vào canvas. Khi nhấp chuột mà đi theo, chúng tôi sẽ kiểm tra tính minh bạch và hành động chỉ dành cho khu vực nhấp chuột không minh bạch:

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

Sự kỳ diệu sẽ xảy ra trong hàm isTransparentUnderMouse, mà cần hai đối số: tử target canvas (this trong phạm vi của trình xử lý nhấp chuột) và dữ liệu sự kiện (e, trong ví dụ này). Bây giờ chúng ta đến với thịt:

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

Đầu tiên, chúng ta nhảy múa xung quanh để có được vị trí chính xác của nguyên tố được đề cập. Chúng ta sẽ sử dụng thông tin đó để chuyển đến phần tử canvas. Các getImageData sẽ cung cấp cho chúng tôi, trong số những thứ khác, một đối tượng data có chứa RGBA của vị trí chúng tôi đã chỉ định.

Nếu tất cả các giá trị đó bằng 0, thì chúng tôi sẽ xem xét tính minh bạch. Nếu không, có một số màu hiện diện. -như- như đã lưu ý trong các ý kiến, giá trị duy nhất chúng ta thực sự cần xem xét là cuối cùng, imgdata[3] trong ví dụ trên. Các giá trị là r (0) g (1) b (2) a (3), và độ trong suốt được xác định bởi a, alpha. Bạn có thể sử dụng phương pháp tương tự này để tìm bất kỳ màu nào ở bất kỳ độ mờ nào mà bạn biết dữ liệu rgba.

Hãy thử nó ra ở đây: http://jsfiddle.net/pJ3MD/1/

(lưu ý: trong ví dụ của tôi, tôi đã sử dụng một hình ảnh mã hóa base64 vì sự an ninh miền tôi đã đề cập Bạn có thể bỏ qua mà phần của mã này, trừ khi bạn cũng có ý định. về việc sử dụng mã hóa base64)

Cùng Ví dụ, với những thay đổi để con trỏ chuột ném vào cho vui: http://jsfiddle.net/pJ3MD/2/

Documentation

+0

+1 cho nỗ lực bạn đã đưa vào câu trả lời này. Ngoài ra +1 vì đó là câu trả lời hay! – Bojangles

+0

đó là ý tưởng tuyệt vời! cảm ơn nhiều! – lviggiani

+0

chỉ là cải tiến thẩm mỹ cho isTransparentUnderMouse: return (imgdata [0] + imgdata [1] + imgdata [2] + imgdata [3] == 0) – lviggiani

4

Bạn có thể thực hiện việc này bằng canvas HTML5. Vẽ hình ảnh vào canvas, đính kèm trình xử lý nhấp chuột vào canvas và trong trình xử lý, kiểm tra xem pixel đã được nhấp vào có trong suốt hay không.

+1

Ah, chúng tôi nghĩ giống nhau về điều này, tôi không thấy câu trả lời của bạn vì phải mất một phút để làm việc đó! Chúc mừng! –

1

cảm ơn bạn chris cho câu trả lời tuyệt vời này

Tôi đã thêm một vài dòng mã để xử lý với nhân rộng vải

vì vậy những gì tôi làm bây giờ là tạo ra một khung của chính xác kích thước pixel hình ảnh đã được vẽ trên đó. tương tự (ví một hình ảnh 220px * 120px):

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

và quy mô vải sử dụng css:

#mainMenu_item{ width:110px; }

và chức năng isTransparentUnderMouse điều chỉnh trông giống như:

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