相对于离线应用,Web SQL Database 等特性,如 Canvas,Video 等媒体应用类的 HTML5 特性我用得比较少,于是今年年初的时候就尝试用这些新特性做点练习,感受一下 HTML5 在媒体应用方面的能力,今天重新翻了一下这些 Demo,整理了两个网页时钟 —— 一个主要用 Canvas 实现,一个主要用 CSS3 实现,为什么是“主要”?因为无论那种方式,都需要 JavaScript 和 HTML 的配合。
首先给出两个 Demo
因为是很简单的内容,所以很难说用那种方式实现会更快,但也不难从这个过程中感受到 Canvas 的魅力,JavaScript 操纵,简单易用的 API ,使到前端开发者用很少的学习成本便能掌握一种 Web 图像处理的方式,对于 HTML5 在图像处理、动画和文本渲染方面的能力也有很大的提升。
接下来简单介绍一下 Canvas 几个常用的 API ,而在介绍这些 API 之前首先贴出上面那个例子的 JavaScript 源码,
var canvas = document.getElementById('clock'); // 获取 Canvas 对象 var clock = canvas.getContext('2d'); // 获取 Canvas 上下文 var canvas2 = document.getElementById('digital'); // 获取 Canvas 对象 var digital = canvas2.getContext('2d'); // 获取 Canvas 上下文 // 重新定义(0, 0)点 clock.translate(canvas.width / 2, canvas.height / 2); // 数字时钟 function theDigital(n, x, y){ var img = new Image(); img.src = 'numbers.png'; switch(n){ case ':': digital.drawImage(img, 183, 0, 15, 30, x, y, 15, 30); break; case '1': digital.drawImage(img, 8, 0, 22, 30, x, y, 22, 30); break; case '2': digital.drawImage(img, 43, 0, 22, 30, x, y, 22, 30); break; case '3': digital.drawImage(img, 78, 0, 22, 30, x, y, 22, 30); break; case '4': digital.drawImage(img, 113, 0, 22, 30, x, y, 22, 30); break; case '5': digital.drawImage(img, 148, 0, 22, 30, x, y, 22, 30); break; case '6': digital.drawImage(img, 8, 30, 22, 30, x, y, 22, 30); break; case '7': digital.drawImage(img, 43, 30, 22, 30, x, y, 22, 30); break; case '8': digital.drawImage(img, 78, 30, 22, 30, x, y, 22, 30); break; case '9': digital.drawImage(img, 113, 30, 22, 30, x, y, 22, 30); break; case '0': digital.drawImage(img, 148, 30, 22, 30, x, y, 22, 30); break; default: break; } } // 刻画表针 function theClock(){ clock.beginPath(); clock.fillStyle='#efefef'; clock.arc(0, 0, 140, 0, 2 * Math.PI, false); clock.fill(); digital.clearRect(90, 17, 220, 40); var time = new Date(), s = time.getSeconds(), m = time.getMinutes(), h = time.getHours(); var dh = h < 10 ? "0" + h : h, dm = m < 10 ? "0" + m : m, ds = s < 10 ? "0" + s : s; dh = new String(dh); dm = new String(dm); ds = new String(ds); h = h > 12 ? (h - 12) + m / 60 : h + m / 60; // 时针 clock.rotate(Math.PI / 6 * h); clock.beginPath(); clock.moveTo(0, 7); clock.lineTo(0, -63); clock.lineWidth = 4; clock.strokeStyle = '#000'; clock.stroke(); clock.rotate(-Math.PI / 6 * h); // 分针 clock.rotate(Math.PI / 30 * m); clock.beginPath(); clock.moveTo(0, 11); clock.lineTo(0, -99); clock.lineWidth = 4; clock.strokeStyle = '#000'; clock.stroke(); clock.rotate(-Math.PI / 30 * m); // 秒针 clock.rotate(Math.PI / 30 * s); clock.beginPath(); clock.moveTo(0, 14); clock.lineTo(0, -126); clock.lineWidth = 2; clock.strokeStyle = '#000'; clock.stroke(); clock.rotate(-Math.PI / 30 * s); // 表中心 clock.beginPath(); clock.fillStyle = '#000'; clock.arc(0, 0, 5, 0, 2 * Math.PI, false); clock.fill(); theDigital(dh.substr(0,1), 95, 17); theDigital(dh.substr(1,1), 114, 17); theDigital(":", 133, 17); theDigital(dm.substr(0,1), 142, 17); theDigital(dm.substr(1,1), 160, 17); theDigital(":", 178, 17); theDigital(ds.substr(0,1), 188, 17); theDigital(ds.substr(1,1), 207, 17); } // 刻画表盘 function dial(){ clock.beginPath(); clock.lineWidth = 10; clock.strokeStyle = '#000'; clock.fillStyle = '#efefef'; clock.arc(0, 0, 155, 0, 2 * Math.PI, false); clock.fill(); clock.stroke(); setInterval(theClock, 1000); } window.onload = dial;
1.getContext()
这是最基本的 Canvas 方法,可以获取一个 Canvas 元素的上下文,并返回一个对象,该对象提供了用于在画布上绘图的方法和属性,因此要想操纵 Canvas ,首先需要调用 getContext() 方法。
例如上面例子中的:
var canvas = document.getElementById('clock'); // 获取 Canvas 对象 var clock = canvas.getContext('2d'); // 获取 Canvas 上下文
获取上下文后,即可使用 clock 对象中的方法和属性绘制图像。
2.translate(x,y)
定义原点(0,0),Canvas 默认使用的坐标系是以左上角为原点,在平面中以右侧为 x 轴正方向,下侧为 y 轴正方向,以 translate 则可以改变这个默认原点。
3.drawImage(img,sx,sy,swidth,sheight,x,y,width,height)
drawImage 可以在画布上绘制图像、画布或视频。最常用的功能是复制图片的某一个部分到画布上。关于这个方法的属性比较多,具体可以参考
http://www.w3school.com.cn/html5/canvas_drawimage.asp
在上例中,Kayo 对时钟的数字部分用到的 0-9 共10个数字和“:”符号使用了雅黑字体,并制作成图片,然后使用 drawImage 把需要用到的部分逐个引用出来,具体这个过程是这样的:
(1)把 10 个数字和“:”做成自己喜欢的样式,并合并到一张图片上
(2)输出时间时判断每个符号是什么
(3)根据判断使用 drawImage 引用(1)中准备好的图片上相应的区域
这个做法的实用意义在于,你可以使用很个性的字体来做这些数字和符号,这样就能在网页上以非常个性的样式显示内容了,英文网站中比较流行的 Canvas 个性文章标题也是使用这个方法制作。
4.绘制路径
beginPath() 表示开始绘制一条路径,或重置当前路径
lineWidth 设置或返回当前绘制线条的宽度
strokeStyle 设置或返回用于笔触的颜色、渐变或模式
fillStyle 设置或返回用于填充绘画的颜色、渐变或模式
arc(x,y,r,sAngle,eAngle,counterclockwise) 创建弧/曲线(用于创建圆或部分圆)
arc() 方法的参数比较复杂,详细参数请参考:http://www.w3school.com.cn/html5/canvas_arc.asp
fill() 填充当前绘图(路径)
stroke() 绘制已定义的路径
5.save() 与 restore()
之所以把 save() 方法和 restore() 方法单独列出来是为了明确一点,这里的 save() 方法并不是用于保存上面的绘制,而 restore() 方法也不是用于撤销绘图,Canvas 绘制的图像会立即显示出来,并不需要保存才显示,这个 save() 的作用是保存当前环境的状态,即平移、放缩、旋转、错切、裁剪等操作的值,而 restore() 则是回到上一次保存的状态,具体来说,这里的“环境状态”指的就是下面的方法和属性的值:
globalAlpha, strokeStyle, fillStyle, lineWidth, lineCap, lineJoin, miterLimit, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, globalCompositeOperation
Canvas 是使用 Immediate-mode (立即模式)工作,即图像绘制完成后,所有相关的绘图结构会立即从内存中丢弃,这点与 DOM 和 SVG 在绘图后仍把绘图结构保存在内存中并不相同。因此开发者想要把状态保存起来就需要利用 save() 方法,每调用一次 save() 方法就会保存一个状态,而 restore() 则可以恢复一次状态。
下面给一个单独的例子说明 save() 和 restore() 的作用:
连续绘制三个逐渐减小的圆,第一个填充颜色为 #efefef ,第二个为 #afafaf ,第三个为 #efefef ,效果如图:
完整的 JavaScript 如下:
var canvas = document.getElementById('round'); // 获取 Canvas 对象 var round = canvas.getContext('2d'); // 获取 Canvas 上下文 // 重新定义(0, 0)点 round.translate(canvas.width / 2, canvas.height / 2); // 绘制圆 function init(){ round.beginPath(); round.fillStyle = '#efefef'; round.arc(0, 0, 155, 0, 2 * Math.PI, false); round.fill(); round.save(); // 保存状态 round.closePath(); round.beginPath(); round.arc(0, 0, 125, 0, 2 * Math.PI, false); round.fillStyle = '#afafaf'; round.fill(); round.closePath(); round.beginPath(); round.arc(0, 0, 95, 0, 2 * Math.PI, false); round.restore(); // 恢复状态 round.fill(); round.closePath(); } window.onload = init;
可以看到,在绘制第一个圆后保存了 Canvas 的状态,即把上面列出的 12 个方法和属性的值保存起来,在例子中只使用了 fillStyle ,因此保存的就是 fillStyle 的值。所以,在绘制第三个圆前恢复了状态,即相当于把 fillStyle 的值重新设置为 '#efefef',绘值第三个圆时就会自动使用这个值。
本文由 Kayo Lee 发表,本文链接:https://kayosite.com/the-experience-of-canvas.html
评论列表
html5基本上就是一堆JS。。
@大发 这样更好,不必额外学习一种方式操纵它!
之前不是报道HTML5耗资源嘛,Canvas,Video此类应用看了就很耗,不过功能还是很牛的
@airoschou drawImage、clearRect等等对画布有重绘操作的方法应该会消耗比较多资源,所以编写时最好优化算法
绘图等方法,里面涉及都一些算法,因此好资源。就好比矢量图每条线条都是一个算法进行勾勒一样。记得貌似是这样子的,不过对html5没怎么研究。
不是很懂。学习中。。。