canvas教程

Html[网页基础],html5语法,让canvas支持jQuery式的链式语法,adm(2)

字号+ 作者:H5之家 来源:H5之家 2015-11-22 17:16 我要评论( )

说实话我对canvas的原生绘图语法很不满意。以下是一段很平常的canvas绘图代码: 12345678910111213141516ctx.arccenterX,centerY,radius,0,PI*2,true;ctx.shadowColor = 'rgba(0,0,0,0.5)';ctx.shadowBlur = 10;ctx

说实话我对canvas的原生绘图语法很不满意。以下是一段很平常的canvas绘图代码:

12345678910111213141516ctx.arc(centerX,centerY,radius,0,PI*2,true);ctx.shadowColor = 'rgba(0,0,0,0.5)';ctx.shadowBlur = "10";ctx.fill();ctx.beginPath();ctx.shadowColor = 'rgba(0,0,0,0)';ctx.moveTo(centerX-radius,centerY);ctx.lineTo(centerX-radius,centerY - 50);ctx.lineTo(centerX+radius,centerY - 50);ctx.lineTo(centerX+radius,centerY);// ctx.lineTo(centerX-radius,centerY);ctx.fill();ctx.beginPath();ctx.fillStyle = 'rgba(255,0,0,1)';ctx.arc(centerX,centerY-50,radius,0,PI*2,true);ctx.fill();

这段代码的语法有个很明显的特点,就是每一句开头都有一个ctx——这个ctx即Canvas的Context2d对象,也就是画布的画笔。

这就是我对canvas绘图最不爽的地方:既然你的每一个操作,每一个属性都是挂在ctx上面的,那么何必有每次都要写ctx呢?不觉得繁琐吗?不可以省略吗?

答案是,还真就不能省略。

如果我们能把每一行的这个ctx去掉,都能省下不少字节的代码。

有的人可能会让我用with,但众所周知with语句会造成效率问题,而且,如果我中途有其他的非ctx的操作,就不得不中断,写更多的with,就会显得不方便。

另外,canvas不支持链式语法也让我郁闷。所谓的链式语法,如果你用过jQuery,肯定会很熟悉并喜欢他:

1$('#div1').show(300).html(p).delay(3000).slideUp(300).remove();

如果canvas支持链式语法,那我们画图时就可以这样:

1ctx.moveTo(500,0).lineTo(500,500).strokeStyle('#f00').stroke();

多么简洁,行云流水啊。但canvas不支持。

所以我就打算修复一下这些问题,一是去掉每句开头的ctx,二是让他支持链式语法。

本来我打算让这个类从canvas的原生CanvasRenderingContext2D上面直接继承,然后改写,但不幸的是,就连chrome和firefox,对canvas的支持都不一样,各自有不少的私有函数,如果程序员企图用firefox中的某个函数套在chrome里执行,那就会报错。

所以,我没有让这个类直接从CanvasRenderingContext2D继承。

所幸的是,canvas还是有一些通用的无疑义的方法,这个类就只实现了这些通用的方法。

由于不能从CanvasRenderingContext2D继承,所以,只能手写这个方法数组了——当然,实际上我不是手写的,我遍历了CanvasRenderingContext2D的原型,然后去掉了其中的私有方法。

不过如此一来,这个类中大部分的代码字节都是这个方法数组占去了。

然后,我新建一个函数,并为函数的原型架上原生的CanvasRenderingContext2D中的方法。

此时我发现了一个问题,就是canvas.context2d中,并不是所有都是“函数”,还包括“属性”,如ctx.lineWidth = 5;类似的。

刚开始我不知所措,以为我的计划要搁浅了,后来发现解决很简单,只要判断此元素是不是一个函数就行了。是函数,就带参数执行;不是函数——那么就肯定是属性了,就把参数赋给这个属性。

完整代码如下,非常简单。

1234567891011121314151617181920212223242526// 让canvas支持链式语法,来自十年灯~function () {var pro = ['save','restore', 'scale', 'rotate', 'translate', 'transform', 'createLinearGradient', 'createRadialGradient', 'getLineDash', 'clearRect', 'fillRect', 'beginPath', 'closePath', 'moveTo', 'lineTo', 'quadraticCurveTo', 'bezierCurveTo', 'arcTo', 'rect', 'arc', 'fill', 'stroke', 'clip', 'isPointInPath', 'measureText', 'clearShadow', 'fillText', 'strokeText', 'strokeRect', 'drawImage', 'drawImageFromRect', 'putImageData', 'createPattern', 'createImageData', 'getImageData', 'lineWidth','strokeStyle','globalAlpha','fillStyle','font','shadowOffsetX','shadowOffsetY','shadowBlur','shadowColor','lineCap','lineJoin','miterLimit'];function XtendCanvas (canvas) {var ctx = canvas.getContext('2d'),fn = function(){},fnP = fn.prototype;for(var j = 0,p=pro[0];p;p=pro[j++]) {fn.prototype[p] = function (p) {return function () {var args = Array.prototype.slice.call(arguments);// console.log(args);if(typeof ctx[p] == 'function') {ctx[p].apply(ctx,args);} else {ctx[p] = args+'';}return fnP;};}(p);}return new fn;};window.XtendCanvas = XtendCanvas;}();

这个类就是一个函数,他接受一个参数,这个参数就是一个canvas对象。他的使用方法如下:

12var cvs = document.getElementById('cvs');var ctx = XtendCanvas(cvs);

然后,你就可以像使用普通的context2d对象来使用这个ctx了,但不同的是,你可以用链式语法了:

1ctx.clearRect(200,y-20,20,20).fillRect(200,y,20,20).clearRect(300,y-10,30,20).fillRect(300,y+10,30,20);

你可以把所有操作都放在一句话里,你也可以随时中断,做其他的事,然后继续。

这个“类”,由于代码短,完全可以嵌入到任何js库之中,不会造成拖累。

代码中肯定有值得改进的地方,大家可以自行完善。但——吃水不忘挖井人,希望大家记得我,最重要的是思路,对吧?

最后我要说的是,这不是一个canvas的增强类,只是改进一下他的语法而已,以后我也许会发布一个canvas的增强类,但要等我学好了再说了。

Posted on 2012.12.21 by 十年灯 in HTML5, Javascript | Leave a comment

原文地址:

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
网友点评