Làm cách nào để thêm trình xử lý sự kiện onClick đơn giản vào thành phần canvas?


128

Tôi là một lập trình viên Java có kinh nghiệm nhưng lần đầu tiên tôi nhìn vào một số công cụ JavaScript / HTML5 sau khoảng một thập kỷ. Tôi hoàn toàn bối rối về những gì nên là điều đơn giản nhất từng có.

Như một ví dụ tôi chỉ muốn vẽ một cái gì đó và thêm một trình xử lý sự kiện cho nó. Tôi chắc chắn rằng tôi đang làm điều gì đó ngu ngốc, nhưng tôi đã tìm kiếm khắp nơi và không có gì được đề xuất (ví dụ: câu trả lời cho câu hỏi này: Thêm thuộc tính onclick vào đầu vào bằng JavaScript ) hoạt động. Tôi đang sử dụng Firefox 10.0.1. Mã của tôi theo sau. Bạn sẽ thấy một số dòng nhận xét và ở cuối mỗi dòng là một mô tả về những gì (hoặc những gì không) xảy ra.

Cú pháp đúng ở đây là gì? Tôi đang phát điên!

<html>
<body>
    <canvas id="myCanvas" width="300" height="150"/>
    <script language="JavaScript">
        var elem = document.getElementById('myCanvas');
        // elem.onClick = alert("hello world");  - displays alert without clicking
        // elem.onClick = alert('hello world');  - displays alert without clicking
        // elem.onClick = "alert('hello world!')";  - does nothing, even with clicking
        // elem.onClick = function() { alert('hello world!'); };  - does nothing
        // elem.onClick = function() { alert("hello world!"); };  - does nothing
        var context = elem.getContext('2d');
        context.fillStyle = '#05EFFF';
        context.fillRect(0, 0, 150, 100);
    </script>

</body>


8
Sử dụng onclickthay vìonClick
noob

1
Để giải thích lý do tại sao những nỗ lực đó không hoạt động ... Một vài bình luận đầu tiên hiển thị cảnh báo ngay lập tức vì bạn đang gọi alert()trực tiếp <script>, thay vì xác định chức năng sẽ gọi alert(). Phần còn lại không làm gì vì viết hoa onclick.
LarsH

Bạn có thể sử dụng lib jsfiddle.net/user/zlatnaspirala/fiddles này , xem bitbucket.org/nikola_l/visual-js . Bạn sẽ nhận được rất nhiều tính năng +
Nikola Lukic

Câu trả lời:


223

Khi bạn vẽ đến một canvasphần tử, bạn chỉ cần vẽ một bitmap ở chế độ ngay lập tức .

Các yếu tố (hình dạng, đường thẳng, hình ảnh) được vẽ không có đại diện bên cạnh các pixel chúng sử dụng và màu sắc của chúng.

Do đó, để có được sự kiện nhấp chuột trên một canvas phần tử (hình dạng), bạn cần nắm bắt các sự kiện nhấp chuột trên canvasphần tử HTML và sử dụng một số phép toán để xác định phần tử nào được nhấp, miễn là bạn đang lưu trữ phần tử chiều rộng / chiều cao và x / y của phần tử .

Để thêm một clicksự kiện vào thành canvasphần của bạn , hãy sử dụng ...

canvas.addEventListener('click', function() { }, false);

Để xác định phần tử nào đã được nhấp ...

var elem = document.getElementById('myCanvas'),
    elemLeft = elem.offsetLeft + elem.clientLeft,
    elemTop = elem.offsetTop + elem.clientTop,
    context = elem.getContext('2d'),
    elements = [];

// Add event listener for `click` events.
elem.addEventListener('click', function(event) {
    var x = event.pageX - elemLeft,
        y = event.pageY - elemTop;

    // Collision detection between clicked offset and element.
    elements.forEach(function(element) {
        if (y > element.top && y < element.top + element.height 
            && x > element.left && x < element.left + element.width) {
            alert('clicked an element');
        }
    });

}, false);

// Add element.
elements.push({
    colour: '#05EFFF',
    width: 150,
    height: 100,
    top: 20,
    left: 15
});

// Render elements.
elements.forEach(function(element) {
    context.fillStyle = element.colour;
    context.fillRect(element.left, element.top, element.width, element.height);
});​

jsFiddle .

Mã này gắn một clicksự kiện vào canvasphần tử và sau đó đẩy một hình dạng (được gọi là elementtrong mã của tôi) vào một elementsmảng. Bạn có thể thêm nhiều như bạn muốn ở đây.

Mục đích của việc tạo ra một mảng các đối tượng là để chúng ta có thể truy vấn các thuộc tính của chúng sau này. Sau khi tất cả các phần tử đã được đẩy lên mảng, chúng tôi lặp lại và kết xuất từng phần tử dựa trên các thuộc tính của chúng.

Khi clicksự kiện được kích hoạt, mã lặp qua các phần tử và xác định xem lần nhấp có vượt qua bất kỳ phần tử nào trong elementsmảng không. Nếu vậy, nó kích hoạt một cái alert(), có thể dễ dàng sửa đổi để làm một cái gì đó như loại bỏ mục mảng, trong trường hợp đó bạn cần một chức năng kết xuất riêng để cập nhật canvas.


Để hoàn thiện, tại sao các nỗ lực của bạn không hoạt động ...

elem.onClick = alert("hello world"); // displays alert without clicking

Này được gán giá trị trả về alert()đến onClicktài sản của elem. Nó ngay lập tức gọi alert().

elem.onClick = alert('hello world');  // displays alert without clicking

Trong JavaScript, '"giống hệt nhau về mặt ngữ nghĩa, từ vựng có thể sử dụng ['"]để trích dẫn.

elem.onClick = "alert('hello world!')"; // does nothing, even with clicking

Bạn đang gán một chuỗi cho thuộc onClicktính của elem.

elem.onClick = function() { alert('hello world!'); }; // does nothing

JavaScript là trường hợp nhạy cảm. Tài onclicksản là phương pháp cổ xưa của việc gắn xử lý sự kiện. Nó chỉ cho phép một sự kiện được gắn với thuộc tính và sự kiện có thể bị mất khi tuần tự hóa HTML.

elem.onClick = function() { alert("hello world!"); }; // does nothing

Một lần nữa , ' === ".


Hmm ... tha thứ cho tôi nếu tôi hiểu lầm - nhưng tôi không nắm bắt được các sự kiện nhấp chuột trên thành phần canvas? Tôi không chắc ý của bạn là bởi yếu tố nào đã được nhấp. Chỉ có một yếu tố trên trang này, phải không?
Giê

Ông có nghĩa là "yếu tố nào trong khung vẽ" - đó là "hình dạng" để nói.
Jovan Perovic

1
Cảm ơn, rất nhiều như vậy - mặc dù tôi không hoàn toàn rõ ràng về cái cuối cùng. Tôi đang theo dõi ví dụ ở đây: developer.mozilla.org/en/DOM/element.onclick (sử dụng hàm ẩn danh mà họ mô tả) và nó hoạt động, ngay cả khi tôi thay đổi nhịp thành canvas. Vì vậy, sẽ không khó để tôi từ từ biến đổi ví dụ của họ thành của tôi để xem tôi đang làm gì sai. Cảm ơn bạn đã phản hồi chi tiết! Giải thích tại sao những nỗ lực khác nhau của tôi là sai đặc biệt hữu ích.
Giê

1
@Jer Đừng lo lắng, nếu bạn có thêm câu hỏi, vui lòng đăng và ping tôi trên Twitter, @alexdickson .
alex

1
@HashRocketSyntax Nó sẽ hoạt động tốt, chỉ cần cập nhật vị trí của các đối tượng của bạn trong bộ nhớ và sử dụng các định nghĩa đó để kết xuất từ
alex

4

Có lẽ rất muộn để trả lời nhưng tôi chỉ đọc nó trong khi chuẩn bị cho 70-480bài kiểm tra của mình và thấy nó hoạt động -

var elem = document.getElementById('myCanvas');
elem.onclick = function() { alert("hello world"); }

Thông báo sự kiện như onclickthay vì onClick.

Ví dụ về thùng rác .


3

Tôi đề xuất và bài viết sau: Nhấn Phát hiện khu vực cho Canvas HTML5 và Cách lắng nghe để nhấp vào các sự kiện trên Hình dạng Canvas trải qua các tình huống khác nhau.

Tuy nhiên, nó không bao gồm addHitRegionAPI, đây phải là cách tốt nhất (sử dụng các hàm toán học và / hoặc so sánh là khá dễ bị lỗi). Cách tiếp cận này được trình bày chi tiết trên developer.mozilla


"[ addHitRegion] đã lỗi thời. Mặc dù nó vẫn có thể hoạt động trong một số trình duyệt, nhưng việc sử dụng nó không được khuyến khích vì nó có thể bị xóa bất cứ lúc nào. Hãy cố gắng tránh sử dụng nó." - từ liên kết dev.moz bạn bao gồm, để lưu người khác nhấp chuột.
Chris

2

Thay thế cho câu trả lời của alex:

Bạn có thể sử dụng bản vẽ SVG thay vì bản vẽ Canvas. Ở đó bạn có thể thêm các sự kiện trực tiếp vào các đối tượng DOM được vẽ.

xem ví dụ:

Tạo một đối tượng hình ảnh svg có thể nhấp bằng onclick, tránh định vị tuyệt đối


1
xin lỗi vì sự nhiệt tình, chỉ là tôi gặp vấn đề trong đó sử dụng SVG là giải pháp rõ ràng và tôi đã không nghĩ đến nó cho đến khi nhận xét của bạn ^^
Elias Dornele

1

Bạn cũng có thể đặt các thành phần DOM, như divtrên đầu khung vẽ đại diện cho các thành phần canvas của bạn và được định vị theo cùng một cách.

Bây giờ bạn có thể đính kèm trình lắng nghe sự kiện cho các div này và chạy các hành động cần thiết.


1

Là một lựa chọn rẻ tiền khác trên khung vẽ hơi tĩnh, sử dụng phần tử img chồng với định nghĩa sơ đồ là nhanh và bẩn. Hoạt động đặc biệt tốt trên các yếu tố vải dựa trên đa giác như biểu đồ hình tròn.


0

Alex Trả lời khá gọn gàng nhưng khi sử dụng xoay ngữ cảnh có thể khó theo dõi tọa độ x, y, vì vậy tôi đã tạo một bản Demo cho thấy cách theo dõi điều đó.

Về cơ bản tôi đang sử dụng chức năng này và cho nó góc & lượng khoảng cách di chuyển trong thiên thần đó trước khi vẽ đối tượng.

function rotCor(angle, length){
    var cos = Math.cos(angle);
    var sin = Math.sin(angle);

    var newx = length*cos;
    var newy = length*sin;

    return {
        x : newx,
        y : newy
    };
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.