首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网站开发 > Web前端 >

canvas中展示对象交互的简陋实现

2012-09-05 
canvas中显示对象交互的简陋实现人比较懒,聊天的时候废话连篇,写文章的时候就懒了..就简单说一下思路,不会

canvas中显示对象交互的简陋实现
人比较懒,聊天的时候废话连篇,写文章的时候就懒了..就简单说一下思路,不会的同学看下思路,不怕我误人子弟就行...会的同学欢迎多多拍砖,每一个砖头都是进步的垫脚石,不胜感激!

起因:
在csdn上一个朋友提问,用什么办法检测canvas上面显示对象的hover方法,记录在本博客的"论坛回帖随手写"分类下面了,有兴趣的同学可以看下。
当时写的时候,只是以实现为目的,没有扩展性,不通用,于是就想些一个通用一点的来着。
但是碍于时间问题,一直拖着,兴许拖着拖着就忘了也未可知。
正好公司决策层改变主意,正在进行的项目有些变更,闲下来就简单实现了个canvas的动画效果和鼠标点击事件的监听。

原理:
[动画]:其实就是使用定时器,window对象的setInterval方法来实现动画,做过flash ActionScript编程的同学可能比较熟悉。
[鼠标事件]:简陋的模型来说鼠标事件其实就是判断鼠标点击在canvas上的位置,然后检测一下点击位置是否在图形区域之内,hover事件则用mousemove事件来实现,当然也可以在setInterval的循环中实现。事件代理,我习惯直接加在canvas上,看有不少同学是在canvas上做了一个div来代理,不清楚其中的好处,有明白的同学也多多指点。
至于多图形遮盖的效果,在之前的那个hover事件监听中有实现。

至于子对象列表、事件冒泡之类的,等过阵闲下来再更新吧。但愿不是遥遥无期...
代码在下面:
有个地方的this是thisthis,是因为论坛的代码格式化有问题,不是写的问题,复制之后请自行修改再运行。在一次点击事件触发后一段时间内不能再触发点击事件是因为alert阻塞线程,但是setInterval仍然会继续执行导致,改成console.log就可以正常打印,并非bug。
that's all.

<!doctype html><html><meta charset="utf-8"><head><title>canvas形状事件代理测试</title><style>html,body{margin:0; padding:0;}</style></head><body><canvas id="cvs" width="500" height="500" style="border:1px solid #333;">狗日的ie..</canvas><script type="text/javascript">// point 类var CPoint = function(x,y){this.x = x;this.y = y;}CPoint.prototype = {getType:function(){return 'point';},hitTestPoint:function(p){return p.x == this.x && p.y == this.y;},toString:function(){return '[object CPoint]';}};// circle 类var CCircle = function(radius){this.x = this.y = 0;this.radius = radius;}CCircle.prototype = {getType:function(){return 'circle';},hitTestPoint:function(p){return (this.x - p.x) * (this.x - p.x) + (this.y - p.y)*(this.y - p.y) <= this.radius * this.radius;},toString:function(){return '[object CCircle]';}}// rectangle 类var CRectangle = function(width,height){this.x = this.y = 0;this.width = width;this.height = height;}CRectangle.prototype = {getType:function(){return 'rectangle';},hitTestPoint:function(p){return p.x > (this.x-this.width/2) && p.x < (this.x + this.width/2) && p.y > (this.y-this.height/2) && p.y < (this.y + this.height/2);},toString:function(){return '[object CRectangle]';}}// 设置root对象var root = [];root.addChild = function (s){this.push(s);}root.start = function (){this.timer = setInterval(function(){UpdateCtx(root.ctx);root.onEnterFrame && root.onEnterFrame();},25);}root.stop = function (){clearInterval(this.timer);}root.toString = function (){return '[object root]';}// 绘制对象方法function DrawShapeOnCtx(ctx,s){ctx.beginPath();ctx.lineWidth = 2;ctx.strokeStyle = '#333'switch(s.getType()){case 'circle':ctx.arc(s.x,s.y,s.radius,0,Math.PI*2,false);break;case 'rectangle':ctx.strokeRect(s.x - s.width/2,s.y-s.height/2,s.width,s.height);break;}ctx.stroke();ctx.closePath();}// 更新canvas方法function UpdateCtx (ctx){ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);for(var i=root.length-1;i>-1;i--)DrawShapeOnCtx(ctx,root[i]);}// 用户自定义部分开始var c = new CCircle(20);;c.x = 100;c.y = 100;var r = new CRectangle(100,20);r.x = 100;r.y = 300;root.addChild(c);root.addChild(r);root.ctx = document.getElementById('cvs').getContext('2d');root.onEnterFrame = function (){c.x += 5;if(c.x > root.ctx.canvas.width-c.radius){c.x = -c.radius;}}root.start();root.ctx.canvas.onclick = function(e){var p = new CPoint(e.clientX,e.clientY);if(r.hitTestPoint(p) || c.hitTestPoint(p)){alert('You have clicked the shape!');};}</script></body></html>

热点排行