如何将简单的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 2012年

1
要详细说明为什么这些尝试无法进行... ...前两条注释会因为您alert()直接调用<script>而立即显示警报,而不是定义将调用的函数alert()。剩下的什么都不做,因为的大小写onclick
LarsH '16

您可以使用此lib jsfiddle.net/user/zlatnaspirala/fiddles,查看bitbucket.org/nikola_l/visual-js。您将获得很多功能+
Nikola Lukic

Answers:


223

绘制canvas元素时,您只是在即时模式下绘制位图。

绘制的元素(形状,线条,图像)除了使用的像素和颜色外没有其他表示形式。

因此,要获取元素(形状)上的click事件,需要存储HTML元素上的click事件,并使用一些数学运算来确定单击了哪个元素,前提是要存储元素的宽度/高度和x / y偏移量。canvas canvas

要将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在我的代码中称为an )推入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

在JavaScript中,'"在语义上是相同的,词法分析器可能使用['"]引号。

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

您正在为的onClick属性分配一个字符串elem

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

JavaScript区分大小写。该onclick属性是附加事件处理程序的古老方法。它仅允许将一个事件附加到该属性,并且在序列化HTML时该事件可能会丢失。

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

再次,' === "


嗯...如果我误会了我-但是我没有捕获到canvas元素上的点击事件吗?我不确定单击什么元素意味着什么。此页面上只有一个元素,对吗?

他的意思是“画布中的哪个元素”-可以说是哪个“形状”。
Jovan Perovic

1
非常感谢,尽管我对最后一个并不清楚。我在这里遵循以下示例: developer.mozilla.org/en/DOM/element.onclick(使用他们描述的匿名函数),即使我将跨度更改为画布,它也可以工作。因此,对于我来说,慢慢地将他们的榜样转变成我的榜样,以查看我在做什么错,并不难。感谢您的详细回复!为什么我的各种尝试是错误的解释特别有帮助。

1
@Jer不用担心,如果您还有其他问题,请随时在Twitter @alexdickson上发帖并ping我。
alex 2012年

1
@HashRocketSyntax它应该可以正常工作,只是更新对象在内存中的位置,并使用这些定义进行渲染即可
alex

4

答案可能很晚了,但我在准备70-480考试时就读了这篇,发现它可以正常工作-

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

请注意,事件是onclick而不是onClick

JS Bin示例。


3

我推荐以下文章:HTML5画布的点击区域检测以及如何在各种情况下在Canvas Shapes上单击事件的侦听

但是,它没有涵盖addHitRegionAPI,它必须是最好的方法(使用数学函数和/或比较很容易出错)。在developer.mozilla上详细介绍这种方法


“ [ addHitRegion]已过时。尽管它在某些浏览器中仍然可以使用,但不鼓励使用它,因为可以随时将其删除。请尝试避免使用它。” -从您包括的dev.moz链接中保存点击。
克里斯



1

作为在某些静态画布上的另一种廉价替代方法,将覆盖的img元素与usemap定义一起使用既快速又肮脏。在基于多边形的画布元素(如饼图)上尤其有效。


0

Alex Answers非常简洁,但是当使用上下文旋转时,可能很难跟踪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
    };
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.