ฉันจะเพิ่มตัวจัดการเหตุการณ์ onClick แบบง่ายให้กับองค์ประกอบ canvas ได้อย่างไร


128

ฉันเป็นโปรแกรมเมอร์ Java ที่มีประสบการณ์ แต่กำลังมองหาสิ่งต่างๆเกี่ยวกับ JavaScript / HTML5 เป็นครั้งแรกในรอบทศวรรษ ฉันนิ่งงันกับสิ่งที่ควรจะง่ายที่สุดเท่าที่เคยมีมา

ตัวอย่างเช่นฉันแค่อยากวาดบางอย่างแล้วเพิ่มตัวจัดการเหตุการณ์เข้าไป ฉันแน่ใจว่าฉันทำอะไรโง่ ๆ แต่ฉันค้นหาจนทั่วแล้วและไม่มีอะไรที่แนะนำ (เช่นคำตอบสำหรับคำถามนี้: เพิ่มคุณสมบัติ onclick เพื่อป้อนข้อมูลด้วย JavaScript ) ฉันใช้ Firefox 10.0.1 รหัสของฉันตาม คุณจะเห็นบรรทัดแสดงความคิดเห็นหลายบรรทัดและในตอนท้ายของแต่ละบรรทัดจะมีคำอธิบายว่าเกิดอะไรขึ้น (หรือไม่เกิดอะไรขึ้น)

ไวยากรณ์ที่ถูกต้องที่นี่คืออะไร? ฉันจะบ้า!

<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
ใช้onclickแทนonClick
noob

1
เพื่ออธิบายรายละเอียดว่าเหตุใดความพยายามเหล่านั้นจึงไม่ได้ผล ... ความคิดเห็นสองสามรายการแรกจะแสดงการแจ้งเตือนทันทีเนื่องจากคุณโทรalert()เข้าโดยตรง<script>แทนที่จะกำหนดฟังก์ชันที่จะเรียกalert()ใช้ ส่วนที่เหลือไม่ได้ทำอะไรเลยเพราะตัวพิมพ์ใหญ่ของonclick.
LarsH

คุณสามารถใช้ lib นี้jsfiddle.net/user/zlatnaspirala/fiddlesลักษณะที่bitbucket.org/nikola_l/visual-js คุณจะได้รับคุณสมบัติมากมาย +
Nikola Lukic

คำตอบ:


223

เมื่อคุณวาดเป็นcanvasองค์ประกอบคุณเพียงแค่วาดบิตแมปในโหมดทันทีโหมดทันที

องค์ประกอบ (รูปทรงเส้นภาพ) ที่จะมีการวาดมีตัวแทนนอกจากพิกเซลที่พวกเขาใช้และสีของพวกเขาไม่มี

ดังนั้นเพื่อให้ได้เหตุการณ์การคลิกบนcanvas องค์ประกอบ (รูปร่าง) คุณต้องจับภาพเหตุการณ์การคลิกบนcanvasองค์ประกอบ HTML และใช้คณิตศาสตร์บางอย่างเพื่อพิจารณาว่าองค์ประกอบใดถูกคลิกหากคุณจัดเก็บความกว้าง / ความสูงขององค์ประกอบและการชดเชย x / y .

หากต้องการเพิ่มclickเหตุการณ์ให้กับcanvasองค์ประกอบของคุณให้ใช้ ...

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

เพื่อตรวจสอบว่าองค์ประกอบใดถูกคลิก ...

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

รหัสนี้แนบclickเหตุการณ์กับcanvasองค์ประกอบจากนั้นดันรูปร่างหนึ่ง (เรียกว่าelementในรหัสของฉัน) ไปยังelementsอาร์เรย์ คุณสามารถเพิ่มได้มากเท่าที่คุณต้องการที่นี่

จุดประสงค์ของการสร้างอาร์เรย์ของออบเจ็กต์คือเพื่อให้เราสามารถสืบค้นคุณสมบัติของวัตถุได้ในภายหลัง หลังจากที่องค์ประกอบทั้งหมดถูกผลักลงในอาร์เรย์แล้วเราจะวนซ้ำและแสดงผลแต่ละองค์ประกอบตามคุณสมบัติของมัน

เมื่อclickเหตุการณ์ถูกทริกเกอร์โค้ดจะวนซ้ำผ่านองค์ประกอบและกำหนดว่าการคลิกอยู่เหนือองค์ประกอบใด ๆ ในelementsอาร์เรย์หรือไม่ หากเป็นเช่นนั้นมันจะเริ่มการalert()ทำงานซึ่งสามารถแก้ไขได้อย่างง่ายดายเพื่อทำบางสิ่งบางอย่างเช่นลบรายการอาร์เรย์ซึ่งในกรณีนี้คุณต้องใช้ฟังก์ชันการแสดงผลแยกต่างหากเพื่ออัปเดตไฟล์canvas.


เพื่อความสมบูรณ์ทำไมความพยายามของคุณไม่ได้ผล ...

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

นี้จะกำหนดค่าตอบแทนของalert()กับทรัพย์สินของonClick elemมันกำลังเรียกใช้ไฟล์alert() .

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

ในจาวาสคริปต์'และ"มีความหมายเหมือนกัน lexer อาจใช้['"]สำหรับเครื่องหมายคำพูด

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

คุณกำลังกำหนดสตริงกับทรัพย์สินของonClickelem

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

JavaScript คำนึงถึงตัวพิมพ์เล็กและใหญ่ onclickคุณสมบัติเป็นวิธีโบราณแนบจัดการเหตุการณ์ อนุญาตให้เชื่อมต่อกับพร็อพเพอร์ตี้ได้เพียงเหตุการณ์เดียวเท่านั้นและเหตุการณ์อาจสูญหายได้เมื่อต่ออนุกรม HTML

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

อีกครั้ง, ' === ".


อืม ... ยกโทษให้ฉันถ้าฉันเข้าใจผิด - แต่ฉันไม่ได้บันทึกเหตุการณ์การคลิกบนองค์ประกอบผ้าใบใช่ไหม ผมไม่แน่ใจว่าสิ่งที่คุณหมายถึงสิ่งที่องค์ประกอบที่ถูกคลิก มีองค์ประกอบเดียวในหน้านี้ใช่ไหม
เจอร์

เขาหมายถึง "องค์ประกอบใดในผืนผ้าใบ" นั่นคือ "รูปร่าง" ที่จะพูด
Jovan Perovic

1
ขอบคุณมาก - แม้ว่าฉันจะไม่ชัดเจนในเรื่องสุดท้าย ฉันทำตามตัวอย่างที่นี่ developer.mozilla.org/en/DOM/element.onclick (โดยใช้ฟังก์ชันที่ไม่ระบุชื่อที่อธิบายไว้) และใช้งานได้แม้ว่าฉันจะเปลี่ยนช่วงเป็นผืนผ้าใบก็ตาม ดังนั้นมันจะไม่ยากสำหรับฉันที่จะค่อยๆเปลี่ยนตัวอย่างของพวกเขาเป็นของฉันเพื่อดูว่าฉันทำอะไรผิด ขอบคุณสำหรับคำตอบโดยละเอียด! คำอธิบายว่าเหตุใดความพยายามต่างๆของฉันจึงผิดพลาดจึงเป็นประโยชน์อย่างยิ่ง
เย

1
@Jer ไม่ต้องกังวลถ้าคุณมีคำถามมากขึ้นรู้สึกฟรีเพื่อโพสต์และ ping me on Twitter, @alexdickson
alex

1
@HashRocketSyntax ควรใช้งานได้ดีเพียงอัปเดตตำแหน่งของวัตถุของคุณในหน่วยความจำและใช้คำจำกัดความเหล่านั้นเพื่อแสดงผลจาก
alex

4

คำตอบอาจจะสายไปมาก แต่ฉันเพิ่งอ่านตอนเตรียม70-480สอบและพบว่ามันใช้ได้ผล -

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

ขอให้สังเกตเหตุการณ์เป็นแทนonclickonClick

ตัวอย่างJS Bin


3

ฉันขอแนะนำบทความต่อไปนี้: Hit Region Detection สำหรับ HTML5 Canvas และวิธีฟังคลิกเหตุการณ์บน Canvas Shapesซึ่งจะผ่านสถานการณ์ต่างๆ

อย่างไรก็ตามไม่ครอบคลุมถึงaddHitRegionAPI ซึ่งต้องเป็นวิธีที่ดีที่สุด (การใช้ฟังก์ชันทางคณิตศาสตร์และ / หรือการเปรียบเทียบมีโอกาสเกิดข้อผิดพลาดได้ง่าย) แนวทางนี้มีรายละเอียดเกี่ยวกับ developer.mozilla


"[ addHitRegion] ล้าสมัยแล้วแม้ว่าอาจยังใช้งานได้ในบางเบราว์เซอร์ แต่ก็ไม่แนะนำให้ใช้งานเนื่องจากสามารถนำออกได้ทุกเมื่อพยายามหลีกเลี่ยงการใช้งาน" - จากลิงค์ dev.moz ที่คุณรวมไว้เพื่อช่วยคนอื่นคลิก
คริส

2

เป็นอีกทางเลือกหนึ่งของคำตอบของ alex:

คุณสามารถใช้ภาพวาด SVG แทนภาพวาดผ้าใบ คุณสามารถเพิ่มเหตุการณ์ลงในวัตถุ DOM ที่วาดได้โดยตรง

ดูตัวอย่าง:

การทำให้วัตถุภาพ svg สามารถคลิกได้ด้วย onclick หลีกเลี่ยงการวางตำแหน่งที่แน่นอน


1
ขอโทษสำหรับความกระตือรือร้นฉันมีปัญหาซึ่งการใช้ SVG เป็นวิธีแก้ปัญหาที่ชัดเจนและฉันไม่ได้คิดจนกว่าความคิดเห็นของคุณ ^^
Elias Dorneles

1

คุณยังสามารถวางองค์ประกอบ DOM เช่นdivบนผืนผ้าใบซึ่งจะแสดงถึงองค์ประกอบผ้าใบของคุณและวางตำแหน่งในลักษณะเดียวกันได้

ตอนนี้คุณสามารถแนบตัวฟังเหตุการณ์กับ div เหล่านี้และเรียกใช้การดำเนินการที่จำเป็น


1

ในฐานะที่เป็นอีกทางเลือกหนึ่งที่มีราคาถูกบนผืนผ้าใบที่ค่อนข้างคงที่การใช้องค์ประกอบ img ที่ซ้อนทับด้วยคำจำกัดความของ usemap นั้นรวดเร็วและสกปรก ทำงานได้ดีโดยเฉพาะอย่างยิ่งกับองค์ประกอบแคนวาสรูปหลายเหลี่ยมเช่นแผนภูมิวงกลม


0

คำตอบของ Alexค่อนข้างเรียบร้อย แต่เมื่อใช้การหมุนบริบทอาจเป็นเรื่องยากที่จะติดตามพิกัด x, y ดังนั้นฉันจึงได้ทำการสาธิตเพื่อแสดงวิธีติดตามสิ่งนั้น

โดยพื้นฐานแล้วฉันกำลังใช้ฟังก์ชันนี้และให้มุมและจำนวนระยะทางที่เดินทางในทูตสวรรค์นั้นก่อนวาดวัตถุ

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
    };
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.