突破canvas语法限制 让他支持链式语法


Posted in HTML / CSS onDecember 24, 2012

先来看一段正常的canvas画图语法:

复制代码
代码如下:

ctx.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();

我对canvas原生语法不爽的有两点:1是每句前面都有写ctx(即canvas的context2d对象),2是每个函数或属性都要占一行,浪费空间。

我对jQuery的链式语法很欣赏,比如:

复制代码
代码如下:

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

所以,我也想用这种语法来进行canvas绘图:
复制代码
代码如下:

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

有个办法就是模拟一个context2d对象,这个对象支持所有的原生context2d方法,但又支持链式。

不过,代码不能太多,多了就没人喜欢用了。

下面就是完整的代码段,这个“类”我取名为XtendCanvas(又是以X开头的哟):

复制代码
代码如下:

// 让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对象,他就会返回一个类似context2d的对象,你可以像普通的context2d一样使用,但不同的是,他支持链式语法了:
复制代码
代码如下:

var cvs = document.getElementById('cvs');
var ctx = XtendCanvas(cvs);
ctx.moveTo(500,0).lineTo(500,500).strokeStyle('#f00').stroke();

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

这段代码并不是对canvas的增强,只是单纯的让他支持链式语法了。但胜在代码少,可以嵌入到任何JS库中,在此我希望能得到你的一个“推荐”

代码中肯定有值得改进的地方,大家可以自行完善。但——吃水不忘挖井人,希望大家记得我,最重要的是思路,对吧?下面就是思路:
大家可以看到,代码中最长的部分,是那个保存方法名的数组pro,核心代码反而很短。为什么我要建这么一个数组呢?

本来我也想直接从CanvasRenderingContext2D继承所有原生方法,但每个浏览器下面遍历这个CanvasRenderingContext2D,结果都不一致。如果我把他们直接继承,那么当你想用chrome中的方法套在firefox里执行,就会报错。

所以我只是把CanvasRenderingContext2D中的通用的,无异议的方法与属性名提取了出来,没办法,只有建一个固定的数组——大家可以自行决定往里面添加你的方法。

方法与属性提取出来了,接着就是把原生的方法加在我的新对象上。我建了一个叫fn的空函数,放置我的方法。

由于数组中的这些元素既有函数,也有属性,所以我在循环中判断了他是否是一个函数,如果是函数,就带参数执行;不是函数——那么就肯定是属性了,就把参数赋给这个属性。

这样大家在碰到设置canvas属性的时候,就不用中断链了,直接把属性值当参数传进去就行了,比如:

复制代码
代码如下:

ctx.strokeStyle('#f00')

最后,关键的关键,就是返回fn,这招是从jQuery学来的,是支持链式语法的关键。

这段中用到了匿名函数,闭包,原型,以及我以前文章讲过的奇怪的for循环。

说起来好像挺简单的,不过我实在是想了很久,希望对大家有用。

在写代码的过程中,我发现chrome的做法很不错,他有一串以set开头的函数,如setStrokeColor,setLineCap等函数,给他们传参数,就可以替代对应的strokeStyle和lineCap等属性,也就是说,他的canvas里面就全是函数而没有属性了那样的话我就不用判断是函数还是是属性了。但firefox里面没有这些,所以我还是只能用前面的思路。

我也把那一串set函数给放出来吧

复制代码
代码如下:

var bak = ['setTransform','setAlpha', 'setCompositeOperation', 'setLineWidth', 'setLineCap', 'setLineJoin', 'setMiterLimit', 'setLineDash','setShadow','setStrokeColor','setFillColor'];

他们的用处一看就懂。你也可以选择一些加入前面代码的pro数组中。

最后,我很奇怪我的代码怎么会没有高亮了。。。如果你都看到最后了,那么还是给个推荐吧,让我也虚荣一把

HTML / CSS 相关文章推荐
利用CSS3的flexbox实现水平垂直居中与三列等高布局
Sep 12 HTML / CSS
CSS Grid布局教程之什么是网格布局
Dec 30 HTML / CSS
CSS3色彩模式有哪些?CSS3 HSL色彩模式的定义
Apr 26 HTML / CSS
CSS3,线性渐变(linear-gradient)的使用总结
Jan 09 HTML / CSS
css3进阶之less实现星空动画的示例代码
Sep 10 HTML / CSS
html5触摸事件判断滑动方向的实现
Jun 05 HTML / CSS
基于 HTML5 Canvas实现 的交互式地铁线路图
Mar 05 HTML / CSS
分享一个H5原生form表单的checkbox特效代码
Feb 26 HTML / CSS
html5 Canvas画图教程(6)—canvas里画曲线之arcTo方法
Jan 09 HTML / CSS
探索HTML5本地存储功能运用技巧
Mar 02 HTML / CSS
CSS 圆形进度栏
Apr 06 HTML / CSS
css3 利用transform-origin 实现圆点分布在大圆上布局及旋转特效
Apr 29 HTML / CSS
HTML5重塑Web世界它将如何改变互联网
Dec 17 #HTML / CSS
如何使用html5与css3完成google涂鸦动画
Dec 16 #HTML / CSS
HTML5使用ApplicationCache接口实现离线缓存技术解决离线难题
Dec 13 #HTML / CSS
HTML5离线缓存在tomcat下部署可实现图片flash等离线浏览
Dec 13 #HTML / CSS
基于HTML5超酷摄像头(HTML5 webcam)拍照功能实现代码
Dec 13 #HTML / CSS
使用HTML5的链接预取功能(link prefetching)给网站提速
Dec 13 #HTML / CSS
HTML5 实现一个访问本地文件的实例
Dec 13 #HTML / CSS
You might like
php读取mysql乱码,用set names XXX解决的原理分享
2011/12/29 PHP
php递归删除目录下的文件但保留的实例分享
2014/05/10 PHP
php修改指定文件后缀的方法
2014/09/11 PHP
基于PHP代码实现中奖概率算法可用于刮刮卡、大转盘等抽奖算法
2015/12/20 PHP
php删除数组指定元素实现代码
2017/05/03 PHP
php 查找数组元素提高效率的方法详解
2017/05/05 PHP
PHP批量删除jQuery操作
2017/07/23 PHP
javascript 计算两个整数的百分比值
2009/12/26 Javascript
Jquery实现无刷新DropDownList联动实现代码
2010/03/08 Javascript
JavaScript中json对象和string对象之间相互转化
2012/12/26 Javascript
前端轻量级MVC框架CanJS详解
2014/09/26 Javascript
JavaScript制作windows经典扫雷小游戏
2015/03/31 Javascript
jQuery实现图片与文字描述左右滑动自动切换的方法
2015/07/27 Javascript
JavaScript类型检测之typeof 和 instanceof 的缺陷与优化
2016/01/13 Javascript
JQuery实现网页右侧随动广告特效
2016/01/17 Javascript
基于JS实现省市联动效果代码分享
2016/06/06 Javascript
非常优秀的JS图片轮播插件Swiper的用法
2017/01/03 Javascript
vue-cli系列之vue-cli-service整体架构浅析
2019/01/14 Javascript
js 实现 list转换成tree的方法示例(数组到树)
2019/08/18 Javascript
vuejs+element UI table表格中实现禁用部分复选框的方法
2019/09/20 Javascript
JS代码检查工具ESLint介绍与使用方法
2020/02/04 Javascript
浅谈JavaScript中你可能不知道URL构造函数的属性
2020/07/13 Javascript
[54:26]完美世界DOTA2联赛PWL S3 Forest vs Rebirth 第一场 12.10
2020/12/12 DOTA
对python中return和print的一些理解
2017/08/18 Python
Python格式化输出%s和%d
2018/05/07 Python
python 自动去除空行的实例
2018/07/24 Python
django项目中新增app的2种实现方法
2020/04/01 Python
使用python脚本自动生成K8S-YAML的方法示例
2020/07/12 Python
详解在Python中使用Torchmoji将文本转换为表情符号
2020/07/27 Python
HTML5视频支持检测(检查浏览器是否支持视频播放)
2013/06/08 HTML / CSS
移动端html5判断是否滚动到底部并且下拉加载
2019/11/19 HTML / CSS
Mytheresa中国官网:德国时尚奢侈品商城
2017/08/04 全球购物
美国婚礼礼品网站:MyWeddingFavors
2018/09/26 全球购物
vue项目实现分页效果
2021/03/24 Vue.js
催款律师函范文
2015/05/27 职场文书
完美处理python与anaconda环境变量的冲突问题
2021/04/07 Python