`
bz5811
  • 浏览: 33012 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

HTML5 canvas 内部元素事件响应

阅读更多

Note: 本文的逻辑主体参考自:http://www.xyhtml5.com/html5-canvas-event-handler.html,但是由于原文有较多小错误且没有最终代码,本文将之改正,添加了一个实例并添加了最终的实现代码,算作改进版吧。

 

Note2: 如果你使用的是xp系统,运行本源码出现了问题,请参考:http://bz5811.iteye.com/admin/blogs/1911666

 

最近做一个项目,需要在页面上画一个小人,然后点击小人的不同部分响应不同的位置。例如,点击左腿,显示“点击的是左腿”,点击右腿,显示“点击的是右腿”。因为项目使用的HTML5,所以理所应当的想到了用canvas来画这个小人,但是发现canvas对象是作为一个整体存在的。也就是说,图形本身实际都是Canvas的一部分,不可单独获取,所以也就无法直接给某个图形增加JavaScript事件。这样,如果想点击小人的左腿,是点击不到的,你点击的是canvas的整个对象。

 

给Canvas元素绑定事件

”由于事件只能达到Canvas元素这一层,所以,如果想进一步深入,识别点击发生在Canvas内部的哪一个图形上,就需要增加代码来进行处理。基本思路是:给Canvas元素绑定事件,当事件发生时,检查事件对象的位置,然后检查哪些图形覆盖了该位置。例如一个矩形,该矩形覆盖x轴10-110、y轴10-110的范围。只要鼠标点击在这个范围里,就可以视为点击了该矩形,也就可以手动触发矩形需要处理的点击事件。思路其实比较简单,但是实现起来还是稍微有点复杂。不仅要考虑这个判断过程的效率,有些地方还需要重新判断事件类型,设置要重新定义一个Canvas内部的捕获和冒泡机制。”

 

首先要做的,是给Canvas元素绑定事件,比如Canvas内部某个图形要绑定点击事件,就需要通过Canvas元素代理该事件:

canvas = document.getElementById('myCanvas');
canvas .addEventListener('click', function(e){
  //当click时运行
}, false);

 接下来需要判断事件对象发生的位置,事件对象e的layerX和layerY属性表示Canvas内部坐标系中的坐标。但是这个属性Opera不支持,Safari也打算移除,所以要做一些兼容写法:

function getEventPosition(ev){
  var x, y;
  if (ev.layerX || ev.layerX == 0) {
    x = ev.layerX;
    y = ev.layerY;
  } else if (ev.offsetX || ev.offsetX == 0) { // Opera
    x = ev.offsetX;
    y = ev.offsetY;
  }
  return {x: x, y: y};
}

 现在有了事件对象的坐标位置,下面就要判断Canvas里的图形,有哪些覆盖了这个坐标。Canvas的isPointInPath方法可以判断当前上下文的图形是否覆盖了某个坐标,比如:

canvas = document.getElementById('myCanvas');
ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.rect(10, 10, 100, 100);
ctx.fill();
ctx.isPointInPath(50, 50);     //true
ctx.isPointInPath(5, 5);     //false

 接下来增加一个事件判断,就可以判断一个点击事件是否发生在矩形上:

canvas.addEventListener('click', function(e){
  p = getEventPosition(e);
  if(ctx.isPointInPath(p.x, p.y)){
    //点击了矩形
  }
}, false);

 以上就是处理Canvas事件的基本方法,但是上面的代码还有局限,由于isPointInPath方法仅判断当前上下文环境中的路径,所以当Canvas里已经绘制了多个图形时,仅能以最后一个图形的上下文环境来判断事件。例如,如果我们最后画的是右腿,那么我们只能判断是否点击了右腿,而不能判断身体的其他部分——右腿最后画。这种问题的解决方法是:当点击事件发生时,重绘所有图形,每绘制一个就使用isPointInPath方法,判断事件坐标是否在该图形覆盖范围内。

为了实现重绘,先画一个小人,然后当点击的时候再重绘小人,每次画一个部分的时候就检查是否点击了此部分,如果点击了,那么将相应的序号保存起来。以下是整个小人的代码。

<!DOCTYPE html>
<html>
<head>
<title>HTML5 Canvas Demo</title>
<!--[if IE]>
  <script type="text/javascript" src="excanvas.js"></script>
<![endif]-->
<script>
//初始时画小人
window.onload=function() {
	var canvas = document.getElementById('myCanvas');
    if (canvas.getContext){
		var ctx = canvas.getContext('2d');
		//画左边头
		ctx.fillStyle='#1c94c4';
		ctx.beginPath();
		ctx.arc(105,75,35,Math.PI/2,Math.PI*1.5,false);
		ctx.fill();
		//画右边头		  
		ctx.beginPath();
		ctx.arc(110,75,35,Math.PI*1.5,Math.PI/2,false);
		ctx.fill();
		//画躯干		
		ctx.beginPath();
		ctx.rect(80,120,55,100);
		ctx.fill();
		//画左臂		
		ctx.beginPath();
		ctx.rect(25,140,50,20);
		ctx.fill();
		//画右臂			
		ctx.beginPath();
		ctx.rect(140,140,50,20);
		ctx.fill();
		//画左腿			
		ctx.beginPath();
		ctx.rect(80,225,20,80);
		ctx.fill();
		//画右腿		
		ctx.beginPath();
		ctx.rect(115,225,20,80);
		ctx.fill();
		//添加事件响应
		canvas.addEventListener('click', function(e){
			p = getEventPosition(e);
			reDraw(p,ctx);
		}, false);
	}
}
//得到点击的坐标
function getEventPosition(ev){
  	var x, y;
  	if (ev.layerX || ev.layerX == 0) {
    	x = ev.layerX;
    	y = ev.layerY;
 	}else if (ev.offsetX || ev.offsetX == 0) { // Opera
    	x = ev.offsetX;
    	y = ev.offsetY;
  	}
  	return {x: x, y: y};
}
//重绘
function reDraw(p,ctx){
	arr = [
		{x:105, y:75, width:Math.PI/2, height:Math.PI*1.5},
		{x:110, y:75, width:Math.PI*1.5, height:Math.PI/2},
		{x:80, y:120, width:55, height:100},
		{x:25, y:140, width:50, height:20},
		{x:140, y:140, width:50, height:20},
		{x:80, y:225, width:20, height:80},
		{x:115, y:225, width:20, height:80}		
	]
	//保存序号的数组,这样,即使一次点多个,也能保存——本例中只能每次点一个
	var whichObject = [];
	for(var i=0; i < arr.length; i++){
		//用圆画头
		if(i<2){
			ctx.fillStyle='#1c94c4';
			ctx.beginPath();
			ctx.arc(arr[i].x,arr[i].y,35,arr[i].width,arr[i].height,false);
			ctx.fill();
			if(p && ctx.isPointInPath(p.x, p.y)){
				whichObject.push(i);
				//修改点中区域的颜色
				ctx.fillStyle='#F39814';
				ctx.beginPath();
				ctx.arc(arr[i].x,arr[i].y,35,arr[i].width,arr[i].height,false);
				ctx.fill();
			}
		//用矩形画躯干
		}else{
			ctx.fillStyle='#1c94c4';
			ctx.beginPath();
			ctx.rect(arr[i].x,arr[i].y, arr[i].width,arr[i].height);
			ctx.fill();
			if(p && ctx.isPointInPath(p.x, p.y)){
				whichObject.push(i);
				ctx.fillStyle='#F39814';
				ctx.beginPath();
				ctx.rect(arr[i].x,arr[i].y, arr[i].width,arr[i].height);
				ctx.fill();
			}
		}
	}
	//显示点击了哪个部分
	//alert("click:" + whichObject[0]);
} 
</script>
</head>
<body>
<div style="margin-left:30px;">
<canvas id="myCanvas" width="600" height="500" style="border: 5px blue solid"></canvas>
<br /><br />
</div>
</body>
</html>

 另:推荐几个快速学习canvas的网址:

Canvas教程:https://developer.mozilla.org/zh-CN/docs/Canvas_tutorial

使用html5 canvas绘制精美图形:http://www.ibm.com/developerworks/cn/web/wa-html5canvas/

Canvas图形事件的另一个实例:http://bbs.blueidea.com/thread-2979405-1-1.html

 

1
0
分享到:
评论
1 楼 buged 2013-10-29  
楼主,你做的这个东东有误差,我的想法是弄7个canvas上去不就各自响应事件了吗

相关推荐

    html5 canvas 画雷达图. 实现内部元素的click,mousemove,mouseout事件.

    在这个场景中,我们关注的是如何利用Canvas实现一个雷达图,并且为雷达图的内部元素添加click、mousemove和mouseout事件,增强用户交互体验。 首先,创建雷达图的基本步骤包括: 1. 获取Canvas元素:通过`document...

    HTML5 Canvas 游戏开发实战PDF+源码

    - Canvas元素是HTML5新增的,通过JavaScript来绘制2D图形。 - 绘图API包括各种线条、形状、路径、图像处理、文字和渐变等方法。 - `getContext('2d')`获取2D渲染上下文,这是进行绘图操作的关键。 2. **Canvas...

    html5 canvas动画 人物怪物移动 鼠标点击控制

    总之,这个实例展示了HTML5 Canvas结合JavaScript在网页上实现互动动画的基本流程,包括图形的绘制、动画的更新以及用户输入的响应。这对于学习HTML5 Canvas技术和游戏开发来说是一个很好的起点,可以帮助开发者理解...

    HTML5 Canvas波浪分割线特效.zip

    综上所述,这个"HTML5 Canvas波浪分割线特效"涉及到HTML5 Canvas的基础使用、动态图形绘制、动画原理、交互设计以及响应式布局等多个方面的技术,是网页开发中一个有趣的实践案例。通过学习和理解这个代码,开发者...

    HTML5 Canvas疯狂气泡动画特效.zip

    总的来说,"HTML5 Canvas疯狂气泡动画特效"充分展示了Canvas的动态绘图能力,结合JavaScript的事件处理和动画机制,创造出了一个生动有趣的交互式页面元素。学习和掌握这些技术,对于提升前端开发者的技能水平,尤其...

    html2canvas.js截高清图案例.zip

    它通过读取DOM结构,然后将HTML元素渲染到一个虚拟的Canvas元素上,这个过程就像是浏览器内部的一个“截图”。由于Canvas支持像素级别的操作,因此可以捕获网页的高清内容。对于高DPI(如Retina)屏幕,...

    HTML5 Canvas条形码生成代码.zip

    HTML5 Canvas条形码生成代码是利用HTML5的Canvas元素结合JavaScript实现的一种技术,它能够帮助开发者在网页上动态创建并展示条形码。Canvas是HTML5中的一个核心特性,提供了一个二维图形画布,允许通过JavaScript...

    EaselJS一个js库可以轻松使用HTML5的canvas元素

    EaselJS是一个强大的JavaScript库,专门设计用于简化HTML5 Canvas元素的使用,为开发者提供了一个高效且功能丰富的工具集,以便在2D环境中构建复杂的交互式应用和视觉效果。这个库的目标是消除Canvas API的复杂性,...

    HTML5 canvas网页二维码生成器.zip

    HTML5的canvas元素是网页开发中的一个强大工具,它允许开发者在网页上动态绘制图形,包括复杂的2D图像。在这个“HTML5 canvas网页二维码生成器”项目中,我们可以看到如何利用canvas来创建自定义的二维码,同时支持...

    HTML5后台管理模板是一款高级的HTML5响应式管理模板。.rar

    例如,`&lt;header&gt;`、`&lt;footer&gt;`、`&lt;nav&gt;`等新元素提供了更好的文档结构,`&lt;canvas&gt;`元素支持动态图形绘制,`&lt;video&gt;`和`&lt;audio&gt;`元素则允许在网页内直接播放多媒体内容。此外,离线存储(离线存储API)和拖放功能...

    html5 svg 中元素点击事件添加方法

    这一点非常重要,因为SVG元素可以独立响应鼠标事件,如click、mouseover、mouseout等,而Canvas则必须依赖于Canvas本身进行事件捕获。 4. 在移动设备,特别是iPad上,可能需要确保SVG元素的点击事件正确地添加。有...

    HTML5 Canvas实现炫目的彩虹泡沫动画效果源码.zip

    1. **Canvas元素**:HTML5中的`&lt;canvas&gt;`标签是图形的画布,通过JavaScript的`canvas.getContext('2d')`方法获取2D渲染上下文,从而进行绘图操作。 2. **绘图路径**:在Canvas上绘制图形时,通常需要先定义一个路径...

    如何在Canvas上的图形/图像绑定事件监听的实现

    在HTML中,我们通常可以轻松地为各种元素(如按钮、输入框等)添加事件监听器来响应用户的交互行为。然而,当涉及到`&lt;canvas&gt;`元素时,情况变得复杂起来。这是因为通过`&lt;canvas&gt;`创建的任何图形或图像都并非独立的...

    canvas实现放大镜

    总的来说,"canvas实现放大镜"涉及到HTML5 canvas的基础操作、图像处理、鼠标事件监听和响应,以及一定的CSS样式应用。通过学习和实践这一功能,开发者不仅可以提升对canvas的理解,还能为用户提供更丰富的交互体验...

    白色纯净简洁的瀑布流布局html5模板_html5 bootstrap 响应式模板UI前端源码.rar

    在这个源码中,可能包含了使用HTML5新特性的元素标记,以及Bootstrap的CSS和JavaScript代码,用于实现响应式布局和交互效果。例如,可能使用了媒体查询(Media Queries)来定义不同屏幕尺寸下的样式,以达到在不同...

    HTML5+Canvas实现随风飘摇摆动的图片特效源码.zip

    在本项目"HTML5+Canvas实现随风飘摇摆动的图片特效源码.zip"中,重点是利用HTML5的Canvas元素来创建一个动态的、图像随风摆动的效果。Canvas是一个基于矢量图形的画布,通过JavaScript可以进行实时的图形绘制和动画...

    基于canvas的15种不同外观时钟js插件.zip

    这个插件充分利用了HTML5的canvas元素,通过纯JavaScript实现,无需CSS代码或任何外部依赖,从而确保了轻量级和高效的性能。 首先,我们要理解canvas在网页开发中的作用。HTML5的canvas是一个矩形区域,允许开发者...

    H5 Canvas多层波浪矢量动画.zip

    在H5技术中,Canvas是HTML5的一个重要组成部分,它提供了在网页上绘制图形的能力,类似于一个画布。"H5 Canvas多层波浪矢量动画.zip"这个资源可能包含了一个利用Canvas元素创建的、具有多层波浪效果的矢量动画示例。...

    H5 Canvas彩色丝带动画特效.zip

    在网页设计中,H5 Canvas元素是一个强大的工具,它允许开发者直接在浏览器上进行图形绘制,从而实现各种复杂的动画效果。"H5 Canvas彩色丝带动画特效"是利用Canvas API来创建的一种动态视觉表现,通常用于提升用户...

    vue+canvas绘制图形

    在`Canvas.vue`内部,我们将定义`&lt;canvas&gt;`标签,并通过JavaScript来操作其上下文(`canvas.getContext('2d')`),实现图形的绘制。 描述中提到的“封装好的绘制圆形、矩形以及不规则图形的方法”,这通常意味着...

Global site tag (gtag.js) - Google Analytics