0

0

使用 HTML5 canvas 进行 Web 绘图

php中文网

php中文网

发布时间:2016-05-17 09:09:41

|

1985人浏览过

|

来源于php中文网

原创

简介: 新的 HTML5 规范旨在帮助开发人员更轻松的编写出各类 Web 应用,以顺应当前 SaaS,云计算以及 RIA 等技术的最新趋势。在 HTML5 得以广泛推广之前,开发人员通常使用 SVG,VML 等技术进行 Web 绘图操作,但这些基于 XML 的绘图语言声明式的绘图方式并不能满足复杂绘图操作在性能上的需求,比如 Web 游戏所需要的像素级别的绘图能力。HTML5 canvas 元素的出现填补了这种不足,开发人员可以使用 JavaScript 脚本语言在 canvas 中进行一系列基于命令的图形绘制操作,本文将通过讲解如何使用 canvas 元素进行基本绘图操作,以及完成简单的动画和用户交互任务,阐明 canvas 在帮助构建 Web 图形类应用时所能够提供的能力。


背景介绍

HTML5 中新引入的 canvas 元素使得 Web 开发人员在无须借助任何第三方插件(如 Flash,Silverlight)的情况下,可以直接使用 JavaScript 脚本在 Web 页面进行绘图。它首次由苹果公司的 Webkit 框架引入实现,并成功运用在 Safari 浏览器中,读者在 这里可以体验到基于 canvas 的精彩示例。目前,canvas 已成为 HTML5 规范中的事实性标准,并且已经被 Firefox 3.0+, Safari 3.0+, Chrome 3.0+, Opera10.0+ 等浏览器所支持。最近(本文撰写之时),IE 也正式宣称将在其 9.0 版本之后,开始对 canvas 元素进行支持。

基于 canvas 的绘图填补了 SVG 绘图的在复杂绘图操作,特别是性能方面的不足,可广泛应用于 Dashboard,2D/3D Game 等 Web 应用中。

基本绘图 API

在了解了什么是 canvas 元素之后,是时候使用 canvas 在 Web 页面上真正进行的绘图操作了。实际上,单独的一个 canvas 标记只是在页面中定义了一块矩形区域,并无特别之处,开发人员只有配合使用 JavaScript 脚本,才能够完成各种图形,线条,以及复杂的图形变换操作,与基于 SVG 来实现同样绘图效果来比较,canvas 绘图是一种像素级别的位图绘图技术,而 SVG 则是一种矢量绘图技术。正鉴于这种本质机理的不同,如何更快速高效的进行 canvas 渲染成为各主流 JavaScript 执行引擎性能比拼的重要指标之一。目前,Chrome 的 V8, Firefox 的 SpiderMonkey 以及 Safari 的 Nitro 等引擎都已经能够很好的满足二维绘图所需的必要性能指标,虽然在运行一些基于 canvas 的游戏时 CPU 占用率还是相对较高,但我们有理由相信随着 NVIDIA 和 AMD 等一系列硬件厂商的参与,硬件加速技术将大大提升 Web 应用的性能。

在开始绘图之前,我们需要首先创建一个指定大小的 canvas,并为其指定一个 id,方便在 JavaScript 脚本中获取该 DOM 实例对象。声明一个 canvas 节点的方式如下所示。

@@######@@

需要指明的是,由于无法保证所有用户使用的浏览器都能够支持 canvas 元素,所以在目前开发基于 canvas 的 Web 应用中需要增加“Fallback content”,以提示用户他们无法正常体验此功能的原因或建议他们去下载最新的浏览器。

这里,好奇的读者可能会问,既然这是一个普通的 DOM 节点,那么便意味着可以通过直接改变其 width 或 height 属性值来改变 canvas 的大小?确实如此,但是,正如之前提到的 canvas 是一种像素级别的绘图方法,因而,一旦动态调整 canvas 的大小,canvas 将被“重置”到一个新的初始状态,即便是如下这种操作,也会将 canvas 内的位图清除并将所有相关属性恢复到初始值的状态。当然,我们也可以把这当作重置 canvas 的小技巧来使用。

@@######@@

简单图形绘制

基于 canvas 的绘图并不是直接在 canvas 标记所创建的绘图画面上进行各种绘图操作,而是依赖画面所提供的 渲染上下文(Rendering Context),所有的绘图命令和属性都定义在渲染上下文当中。在通过 canvas id 获取相应的 DOM 对象之后首先要做的事情就是获取渲染上下文对象。 渲染上下文与 canvas 一一对应,无论对同一 canvas 对象调用几次 getContext() 方法,都将返回同一个上下文对象。目前,所有支持 canvas 标签的浏览器都支持 2D 渲染上下文,可以使用如下的代码来获取该对象。

@@######@@

除此之外,在不久的将来,开发人员还会能够得到基于 OpenGL 的 3D 渲染上下文以在 canvas 中进行 3D 绘图。

与 SVG 不同,canvas 原生支持的基本图形只有矩形一种,至于其他的圆形,多边形等图形则都由路径来负责绘制实现。清单 1 展示了如何使用渲染上下文中的矩形绘图方法完成了图 1 所示图形。


图 1. 清单 1 对应的示例图形
图 1. 清单 1 对应的示例图形

清单 1. 绘制 canvas 矩形
@@######@@

绘制路径

在开始动手绘制路径之前,首先需要明确的是:矩形绘制 API 是一种即时性的 API,他会在相应的绘图函数执行完毕之后,将图形即时的渲染在画面上。然而路径绘制 API 并非如此,完整的路径绘制过程大致可以分为如下两个阶段:

  • 定义路径轮廓:

在每个 canvas 实例对象中都拥有一个 path 对象,创建自定义图形的过程就是不断对 path 对象操作的过程。每当开始一次新的图形绘制任务,都需要先使用 beginPath() 方法来重置 path 对象至初始状态,进而通过一系列对 moveTo/lineTo 等画线方法的调用,绘制期望的路径,其中 moveTo(x, y) 方法设置绘图起始坐标,而 lineTo(x,y) 等画线方法可以从当前起点绘制直线,圆弧以及曲线到目标位置。最后一步,也是可选的步骤,是调用 closePath() 方法将自定义图形进行闭合,该方法将自动创建一条从当前坐标到起始坐标的直线。

  • 绘制路径

定义完路径的轮廓,此时 canvas 画面中没有显示任何路径,开发人员还可以对路径进行修改。一旦确定完成,则需要继续调用 stroke()/fill() 函数来完成将路径渲染到画面的最后一步。路径的轮廓颜色和填充颜色由 strokeStyle 和 fillStyle 属性决定。

清单 2 绘制一个图 2 所示半圆弧,并通过 closePath() 方法完成图形的闭合。

立即学习前端免费学习笔记(深入)”;


图 2. 清单 2 对应的示例图形
图 2. 清单 2 对应的示例图形

清单 2. 绘制 canvas 路径
@@######@@

二维变形

Canvas 绘图中另一个重要的概念是 绘画状态(Drawing State),绘画状态反映了渲染上下文当前的瞬时状态,开发人员可以通过对绘画状态的保存 / 恢复操作而快速的回到之前使用的各种属性和变形操作。绘画状态主要由以下三个部分构成:

  • 当前的变形矩阵(transformation matrix)
  • 当前的裁剪区域(clipping region)
  • 当前上下文中的属性,比如 strokeStyle, fillType, globalAlpha, font 等等。

需要指出的是,当前路径对象以及当前的位图都不包含在绘画状态之中,路径是持续性的对象,如前文所讲,只有通过 beginPath() 操作才会进行重置,而位图则是 canvas 的属性,并非属于渲染上下文的。

开发人员可以使用 save 和 restore 两种方法来保存和恢复 canvas 状态,每调用 save 方法,都会将当前状态压入堆栈中,而相应的 restore 方法则会从堆栈中弹出一个状态,并将当前画面恢复至该状态。绘画状态在 canvas 图形变形操作中应用极为广泛,也非常重要,因为调用一个 restore 方法远比手动恢复先前状态要简单许多,因而,一个较好的习惯是在做变形操作之前先保存 canvas 状态。

二维绘图的常用变形操作在 canvas 中都可到了很好的支持,包括平移(Translate),旋转(Rotate),伸缩(Scale)等等。由于所有的变形操作都基于变形矩阵,因而开发人员始终需要记住一点的就是,一旦没有使用 save/restore 操作保持住原来的绘图状态,那么后续的绘图操作,都会在当前所应用的变形状态下完成。清单 3 使用平移和旋转方法绘制了如下所示画面。


图 3. 清单 3 所示示例图形
图 3. 清单 3 所示示例图形

清单 3. 使用平移 / 旋转变形方法绘制复杂位图
@@######@@

像素级绘图

JTBC网站内容管理系统5.0.3.1
JTBC网站内容管理系统5.0.3.1

JTBC CMS(5.0) 是一款基于PHP和MySQL的内容管理系统原生全栈开发框架,开源协议为AGPLv3,没有任何附加条款。系统可以通过命令行一键安装,源码方面不基于任何第三方框架,不使用任何脚手架,仅依赖一些常见的第三方类库如图表组件等,您只需要了解最基本的前端知识就能很敏捷的进行二次开发,同时我们对于常见的前端功能做了Web Component方式的封装,即便是您仅了解HTML/CSS也

下载

像素级别的绘图操作是 canvas 绘图区别于 SVG,VML 等绘图技术的最为明显特征之一,渲染上下文提供了 createImageData, getImageData, 和 putImageData 三种方法来进行针对像素的操作,所基于的对象都是 imageData 对象。imageData 对象包含 width、height 和 data 三个属性,其中 data 包含了 width × height × 4 个像素值,之所以乘以 4,在于每个像素都有 RGB 值和透明度 alpha 值。

清单 4 中所示代码为上一节中示例图形增添了简单的颜色反转滤镜效果,通过调用 getImageData(x,y,width,height) 方法获取以(x,y)为左上坐标的矩形区域内所有像素,而后对所有像素的 RGB 值做取反操作,最后通过 putImageData(imageData, x, y)将修改后的像素值重新绘制到在 canvas 上。


图 4. 清单 4 所示示例图形
图 4. 清单 4 所示示例图形

清单 4. 实现简单滤镜效果
@@######@@

实现动画效果

Canvas 并非为了制作动画而出现,自然没有动画制作中帧的概念。因而,使用定时器不断的重绘 canvas 画面成为了实现动画效果的通用解决方式。Javascript 中的 setInterval(code,millisec) 方法可以按照指定的时间间隔 millisec 来反复调用 code 所指向的函数或代码串,这样,通过将绘图函数作为第一个参数传给 setInterval 方法,在每次被调用的过程中移动画面中图形的位置,来最终达到一种动画的体验。需要注意的一点是,虽然 setinterval 方法的第二个参数允许开发人员对绘图函数的调用频率进行设定,但这始终都是一种最为理想的情况,由于这种绘图频率很大程度上取决于支持 canvas 的底层 JavaScript 引擎的渲染速度以及相应绘图函数的复杂性,因而实际运行的结果往往都是要慢于指定绘图频率的。

清单 5 显示了一个小弹力球动画效果,在球没有到达四周边界时,绘图方法不断的移动所绘小球的横纵坐标。并且,在每次重绘之前,都是用 clear 方法将之前的画面清除。


清单 5. 实现小弹力球动画
@@######@@


提高可访问性

一款优秀的 Web 应用必须要做到的就是提供给用户很好的可访问性,这包括对鼠标,键盘以及快捷键等操作的响应,canvas 画面的本质仍是一个 DOM 节点,因而开发人员可以通过常规的方法来处理响应。这里,与基于 SVG 的绘图不同,由于 SVG 是一种基于 XML 的声明式的绘图方式,因而,SVG 中任何的图形都可以作为一个独立的 DOM 节点去接收并响应特定事件,而 canvas 由于其像素绘图的本质,则只可以在 canvas 元素节点去处理。

图 5 所示示例代码,当鼠标在 canvas 中移动时,鼠标当前相对于 canvas 中的横纵坐标将实时输出到上方提示信息区域;当用户在 canvas 中单击鼠标左键,将在相应位置创建一个蓝色小球,而后用户可以通过键盘上的左 / 右方向键对蓝色小球进行控制,使其进行横向的移动。示例代码如清单 6 所示。


图 5. 清单 6 所示示例展现


清单 6. 实现 canvas 对方向键和鼠标点击事件的响应
@@######@@

这里我们对鼠标的移动,单击操作进行响应,在实际应用中可以视特定应用的需求,增加对鼠标摁下,松开或双击等更为丰富操作的响应,增强应用的可访问性。

细心的读者可能发现,在通过不断重绘画面以达到动画效果的过程中,我们的重绘方法首先做的事情都是调用 clearRect(x, y, width, height) 方法将原画面清空,这种销毁而后重绘的方式丢失了之前的画面,使得开发人员不得不重绘整幅画面,这在性能上是难以接受的,一种可行的做法是通过多个 canvas 叠加的方式,根据不同 canvas 上的不同刷新频率,分别完成各自的重绘任务。这种多 canvas 技巧,在处理绘图类应用中最为常见的“撤销”操作时也非常有效,所有的绘图都发生在上层 canvas,只有被用户确认的画面,才会被绘制到底层 canvas 上。鉴于本文所讨论技术范围,这里不做过多讲解,有兴趣的读者可以通过本文参考文献所列资源,进行进一步的深入学习。

总结

本文对 HTML5 新引入的 canvas 元素在 Web 绘图中所扮演的角色和所发挥的作用做了最基本的介绍,其中包括使用 canvas 完成基本的 Web 绘图,动画和交互任务,虽然 Flash,Silverlight 也都可以完成相同的任务,甚至在性能上更胜一筹,但是作为一种不依赖任何插件的标准 Web 像素级绘图技术,我们有理由相信随着各大浏览器厂商的加入,canvas 将会更加成熟完善,也会有更多基于 canvas 的绘图类应用不断涌现。


本文由HTML5中国网站小编整理转发,转载请注明出处。

  
 Fallback content, in case the browser does not support Canvas. 
  
 document.getElementById("canvas").width = document.getElementById("canvas").width; 
 var context = document.getElementById("canvas").getContext("2d"); 
				 
 function drawRect(){ 
 var canvas = document.getElementById('canvas'); 
 if (canvas.getContext){ 
 var ctx = canvas.getContext('2d');  // 获取 2D 渲染上下文
		
 ctx.clearRect(0,0,300,200)  ;// 清除以(0,0)为左上坐标原点,300*200 矩形区域内所有像素
 ctx.fillStyle = '#00f';   // 设置矩形的填充属性,#00f 代表蓝色
 ctx.strokeStyle = '#f00';  // 设置矩形的线条颜色,#f00 代表红色
 ctx.fillRect(50,25,150,80); // 使用 fillStyle 填充一个 150*80 大小的矩形
 ctx.strokeRect(45,20, 160, 90);  // 以 strokeStype 属性为边的颜色绘制一个无填充矩形
     } 
 } 
				 
 function draw(){ 
 var canvas = document.getElementById('canvas'); 
	 if (canvas.getContext){ 
		 var ctx = canvas.getContext('2d'); 
 ctx.fillStyle = '#00f'; 
		 ctx.strokeStyle = '#f00'; 
		 ctx.beginPath(); 
 ctx.arc(75,75,30,0,Math.PI, false);  // 绘制一条半圆弧线
 ctx.closePath();    // 自动绘制一条直线来关闭弧线。若不调用此方法,将仅仅显示一条半圆弧
 ctx.fill();      // 可以尝试注释掉 fill 或者 stroke 函数,观察图形的变化
 ctx.stroke();  
	 } 
 } 
				 
 function drawPointCircle(){  
 var canvas = document.getElementById('canvas');  
	 if (canvas.getContext){ 
		 var ctx = canvas.getContext('2d');  
 ctx.translate(150,150);   // 将 canvas 的原点从 (0,0) 平移至(150,150)
 for (i=1;i<=2;i++){        // 绘制内外 2 层
 if ((i % 2) == 1) {ctx.fillStyle = '#00f';} 
 else{ ctx.fillStyle = '#f00'; } 
 ctx.save();             // 保持开始绘制每一层时的状态一致
 for (j=0;j<=i*6;j++){   // 每层生成点的数量
 ctx.rotate(Math.PI/(3*i));  // 绕当前原点将坐标系顺时针旋转 Math.Pi/(3*i) 度
				 ctx.beginPath(); 
				 ctx.arc(0,20*i,5,0,Math.PI*2,true); 
 ctx.fill();         // 使用 fillType 值填充每个点
 } 
 ctx.restore();   
		 } 
	 } 
 } 
				 
 function revertImage(){ 
 var canvas = document.getElementById('canvas'); 
 if (canvas.getContext){ 
 var context = canvas.getContext('2d'); 
 // 从指定的矩形区域获取 canvas 像素数组
 var imgdata = context.getImageData(100, 100, 100, 100); 
 var pixels = imgdata.data; 

 // 遍历每个像素并对 RGB 值进行取反
 for (var i=0, n=pixels.length; i
				 
  
				 
  

相关文章

HTML速学教程(入门课程)
HTML速学教程(入门课程)

HTML怎么学习?HTML怎么入门?HTML在哪学?HTML怎么学才快?不用担心,这里为大家提供了HTML速学教程(入门课程),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Python 自然语言处理(NLP)基础与实战
Python 自然语言处理(NLP)基础与实战

本专题系统讲解 Python 在自然语言处理(NLP)领域的基础方法与实战应用,涵盖文本预处理(分词、去停用词)、词性标注、命名实体识别、关键词提取、情感分析,以及常用 NLP 库(NLTK、spaCy)的核心用法。通过真实文本案例,帮助学习者掌握 使用 Python 进行文本分析与语言数据处理的完整流程,适用于内容分析、舆情监测与智能文本应用场景。

10

2026.01.27

拼多多赚钱的5种方法 拼多多赚钱的5种方法
拼多多赚钱的5种方法 拼多多赚钱的5种方法

在拼多多上赚钱主要可以通过无货源模式一件代发、精细化运营特色店铺、参与官方高流量活动、利用拼团机制社交裂变,以及成为多多进宝推广员这5种方法实现。核心策略在于通过低成本、高效率的供应链管理与营销,利用平台社交电商红利实现盈利。

109

2026.01.26

edge浏览器怎样设置主页 edge浏览器自定义设置教程
edge浏览器怎样设置主页 edge浏览器自定义设置教程

在Edge浏览器中设置主页,请依次点击右上角“...”图标 > 设置 > 开始、主页和新建标签页。在“Microsoft Edge 启动时”选择“打开以下页面”,点击“添加新页面”并输入网址。若要使用主页按钮,需在“外观”设置中开启“显示主页按钮”并设定网址。

16

2026.01.26

苹果官方查询网站 苹果手机正品激活查询入口
苹果官方查询网站 苹果手机正品激活查询入口

苹果官方查询网站主要通过 checkcoverage.apple.com/cn/zh/ 进行,可用于查询序列号(SN)对应的保修状态、激活日期及技术支持服务。此外,查找丢失设备请使用 iCloud.com/find,购买信息与物流可访问 Apple (中国大陆) 订单状态页面。

136

2026.01.26

npd人格什么意思 npd人格有什么特征
npd人格什么意思 npd人格有什么特征

NPD(Narcissistic Personality Disorder)即自恋型人格障碍,是一种心理健康问题,特点是极度夸大自我重要性、需要过度赞美与关注,同时极度缺乏共情能力,背后常掩藏着低自尊和不安全感,影响人际关系、工作和生活,通常在青少年时期开始显现,需由专业人士诊断。

7

2026.01.26

windows安全中心怎么关闭 windows安全中心怎么执行操作
windows安全中心怎么关闭 windows安全中心怎么执行操作

关闭Windows安全中心(Windows Defender)可通过系统设置暂时关闭,或使用组策略/注册表永久关闭。最简单的方法是:进入设置 > 隐私和安全性 > Windows安全中心 > 病毒和威胁防护 > 管理设置,将实时保护等选项关闭。

6

2026.01.26

2026年春运抢票攻略大全 春运抢票攻略教你三招手【技巧】
2026年春运抢票攻略大全 春运抢票攻略教你三招手【技巧】

铁路12306提供起售时间查询、起售提醒、购票预填、候补购票及误购限时免费退票五项服务,并强调官方渠道唯一性与信息安全。

122

2026.01.26

个人所得税税率表2026 个人所得税率最新税率表
个人所得税税率表2026 个人所得税率最新税率表

以工资薪金所得为例,应纳税额 = 应纳税所得额 × 税率 - 速算扣除数。应纳税所得额 = 月度收入 - 5000 元 - 专项扣除 - 专项附加扣除 - 依法确定的其他扣除。假设某员工月工资 10000 元,专项扣除 1000 元,专项附加扣除 2000 元,当月应纳税所得额为 10000 - 5000 - 1000 - 2000 = 2000 元,对应税率为 3%,速算扣除数为 0,则当月应纳税额为 2000×3% = 60 元。

35

2026.01.26

oppo云服务官网登录入口 oppo云服务登录手机版
oppo云服务官网登录入口 oppo云服务登录手机版

oppo云服务https://cloud.oppo.com/可以在云端安全存储您的照片、视频、联系人、便签等重要数据。当您的手机数据意外丢失或者需要更换手机时,可以随时将这些存储在云端的数据快速恢复到手机中。

121

2026.01.26

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.3万人学习

Node.js 教程
Node.js 教程

共57课时 | 9.5万人学习

CSS3 教程
CSS3 教程

共18课时 | 4.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号