整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

HTML界的“小飞人”-详解Canvas优越性能和实际应用

oogle Docs宣布将会把HTML迁移到基于Canvas渲染,这一消息的出现再次把几年前随HTML5诞生的标签重新推到了人们视线之中。Canvas在刚推出时主打的优势就是更快的渲染速度,堪称HTML届的“小飞人”,刷新了人们对Web页面元素绘制速度的印象。但Canvas的优势仅限于此吗?

(图片来源于网络)

HTML绘图届的前辈:SVG

Canvas是HTML5时代引入的“新”标签。与很多标签不同,Canvas不具有自己的行为,只将一组API 展现给客户端 JavaScript ,让开发者使用脚本把想绘制的东西画到一张画布上。

在HTML5之前,人们通常使用SVG来在页面上绘制出图形。SVG使用XML来定义图形,就像使用HTML标签和样式定义DIV一样,我们也可以将一个空白的DIV想象为长方形的SVG,两者的设计思想是相通的,SVG的本质就是一个DOM元素。而Canvas则不同,Canvas提供的是 JavaScript 的绘图 API,而不是像 SVG那样使用XML 描述绘图,通过JavaScript API直接完成绘制,比起修改XML来说要更简便、更直接。

除了定义的方式不同,Canvas和DOM(当然也包含SVG)的差异更多的体现在浏览器的渲染方式上。

浏览器在做页面渲染时,Dom元素是作为矢量图进行渲染的。每一个元素的边距都需要单独处理,浏览器需要将它们全都处理成像素才能输出到屏幕上,计算量十分庞大。当页面上内容非常多,存在大量DOM元素的时候,这些内容的渲染速度就会变得很慢。

而Canvas与DOM的区别则是Canvas的本质就是一张位图,类似img标签,或者一个div加了一张背景图(background-image)。所以,DOM那种矢量图在渲染中存在的问题换到Canvas身上就完全不同了。在渲染Canvas时,浏览器只需要在JavaScript引擎中执行绘制逻辑,在内存中构建出画布,然后遍历整个画布里所有像素点的颜色,直接输出到屏幕就可以了。不管Canvas里面的元素有多少个,浏览器在渲染阶段也仅需要处理一张画布。

然而这样更加强大的功能,不可避免的让使用canvas渲染有很高的门槛。Google Docs在构建Canvas的过程中重新定义了往常已经被人们所熟悉的内容,例如精确定位、文本选择、拼写检查、重画调优等。为什么更多开发者还是选择了接纳Canvas这个门槛更高的技术路线呢?这就得回到Canvas的最大优势:渲染性能。

Canvas的渲染模式

这里的渲染是指浏览器将页面的代码呈现为屏幕上内容的过程。Canvas和Dom的渲染模式完全不同,搞清楚这个差异对理解Canvas的性能优势至关重要。

Dom:驻留模式

驻留模式(Retained Mode)是Dom在浏览器中的渲染模式。下图粗略展示了这一过程的工作流程。

DOM的核心是标签,一种文本标记型语言,多样性很强且多个标签之间存在各种关联(如在同一个DIV下设置为float的子DIV)。浏览器为了更好的处理这些DOM元素,减少对绘制API的调用,就设计了一套将中间结果存放于内存的“驻留模式”。首先,浏览器会将解析DOM相关的全部内容(包含HTML标签、样式和JavaScript),将其转化为场景(scene)和模型(model)存储到内存中,然后再调用系统的绘制API(如Windows程序员熟悉的GDI/GDI+),把这些中间产物绘制到屏幕。

驻留模式通过场景和模型缓存减少了对绘制API的调用频次,将性能压力转移到场景和模型生成阶段,即浏览器需要根据DOM上下文和BOM中的尺寸数据,“自行判断”每一个元素的绘制结果。

Canvas:快速模式

Canvas采用了和DOM不同的快速模式(Immediate Mode),让我们先来看看快速模式是如工作的:

与驻留模式相比,快速模式将场景和模型的生成从浏览器移交给了开发者。开发者在设计页面时,就通过Canvas的JavaScript API定义了画布内所有元素的绘制方式。浏览器只需要简单的执行这些脚本即可,而不需要像渲染DOM一样逐个处理子元素了。

在快速模式中,页面的绘制性能得到了大幅提升。但开发者不仅需要指定什么需要画,还要创建和维护一个模型。此外,开发者还需要管理好当前场景重绘时带来的改变,以及响应用户的点击或输入操作等。

Canvas的应用优点

上面介绍的两种不同的模式直接造成了Dom和Canvas的性能差异。对于使用快速模式渲染的Canvas而言,浏览器的每次重绘都是基于代码的,不存在能让处理流程变慢的多层解析,所以它真的很快。除了快之外,Canvas的灵活性也大大超出DOM。我们可以通过代码精确的控制如何、何时绘制出我们想要的效果。

在资源消耗上,DOM的驻留模式意味着场景中每增加一点东西就需要额外消耗一些内存,而Canvas并没有这个问题。这个差异会随着页面元素的数量增多而愈加明显。以B端的企业应用场景为例,表单那种数据量比较小的场景,不同渲染模式带来的效果差异并不明显;但在工业制造、金融财会等类Excel电子表格操作的场景下,单元格数量动辄便是上百万(5万行x 20列)甚至上亿个,浏览器需要对表格所有单元格本身内容进行渲染,同时还涉及到丰富的数据处理,情况就完全不同了。

(Web页面上的电子表格,包含1百万个单元格)

在Canvas出现之前,在前端渲染表格时只能通过构建复杂的DOM来实现。这种方式下,浏览器的性能成为了Web应用瓶颈,让很多开发者放弃了在浏览器上实现电子表格的想法。

在Canvas出现后,快速模式带来的性能优势无疑是一个巨大的亮点,大量、复杂的DOM渲染处理带来的性能问题终于有了解决途径。

回到电子表格的应用场景,业内已经出现了使用Canvas绘制画布的表格组件,这类组件在渲染数据层时不仅无需重复创建和销毁DOM元素,在画布的绘制过程中,也比Dom元素渲染的限制更少。除了表格之外,Canvas也为数字孪生可视化大屏、页面游戏等场景带来了变革。

(数字孪生大屏,精确控制各种形状、样式)

总结

总结一下,在渲染模式上,Canvas站在了DOM的对面,浏览器对其内容一无所知,一切渲染的权利回到了开发者的手上,这个改变带来了显著的性能优势。此外,我们可以使用Canvas绘制种类更为丰富的UI元素,如线形、特殊图形等,通过画法逻辑,还可以实现更加精准的UI界面渲染,解决了浏览器差异造成的样式误差,让更多应用场景可以顺利迁移到Web平台上来。

lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

<html>

<body>

<canvas id='canvas'></canvas>

<div id="write"></div>

</body>

</html>

<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>

<script>

//画布

var c=document.getElementById('canvas');

var ctx=c.getContext('2d');

//画布尺寸

var h=650;

var w=800;

c.width=w;

c.height=h;

//背景数量

var num=100;

//大红尺寸

var gh=h/num;

var gw=w/num;

//小绿尺寸

var gamex=40;

var gamey=30;

//背景布置

function bk(){

for(var x=0;x<num;x++){

for(var y=0;y<num;y++){

ctx.fillStyle="green";

ctx.fillRect(10*(x-1)+x,10*(y-1)+y,gw,gh);

}

}

}

//定义小绿数量

var sts=new Array();

//定义小红数量

var drs=new Array();

//小红小绿范围内相遇删除对方

function dels(){

if(sts.length>0){

for(var i=0;i<sts.length;i++){

//范围大小

var a=sts[i]['x']+20;

var b=sts[i]['x']-20;

var aa=sts[i]['y']+20;

var bb=sts[i]['y']-20;

$('#write').text(a+'---'+b);

for(var s=0;s<drs.length;s++){

//判断是否在范围内

if((drs[s]['x']<a && drs[s]['x']>b) && (drs[s]['y']<aa && drs[s]['y']>bb)){

//sts.splice(i,1);//删除小绿

drs.splice(s,1);//删除小红

}

}

}

}

}

//小红数量循环

function drss(){

var dr=new Array();

dr['x']=Math.floor((Math.random()*w)+1);

dr['y']=0;

//dr['y']=Math.floor((Math.random()*h)+1);

drs.push(dr);

if(drs.length>0){

for(var i=0;i<drs.length;i++){

if(drs[i]['y']>h){

drs.splice(i,1);

}else{

drs[i]['y']+=1;

}

ctx.fillStyle="orange";

ctx.fillRect(drs[i]['x'],drs[i]['y'],gw,gh);

}

}

}

//小绿数量循环

function st(){

ctx.fillStyle="black";

var st=new Array();

st['x']=10*(gamex-1)+gamex+10;

st['y']=10*(gamey-1)+gamey-10;

sts.push(st);

ctx.fillRect(10*(gamex-1)+gamex+10,10*(gamey-1)+gamey-10,gw,gh);

}

//小绿移动

function stsup(){

if(sts.length>0){

for(var i=0;i<sts.length;i++){

if(sts[i]['y']<0){

sts.splice(i,1);

}else{

sts[i]['y']-=1;

}

ctx.fillStyle="red";

ctx.fillRect(sts[i]['x'],sts[i]['y'],gw,gh);

}

}

}

//大红位置移动

function game(gamex,gamey){

ctx.fillStyle="red";

//ctx.fillRect(10*(gamex-1)+gamex,10*(gamey-1)+gamey,gw,gh);

ctx.fillRect(10*(gamex-1)+gamex,10*(gamey-1)+gamey,20,20);

}

bk();

game(gamex,gamey);

//时间戳

setInterval(function(){

//按键判断

document.onkeydown=function(event){

var e = event || window.event || arguments.callee.caller.arguments[0];

if(e.keyCode=='37'){

gamex=gamex-1;

}

else if(e.keyCode=='38'){

gamey=gamey-1;

}

else if(e.keyCode=='39'){

gamex=gamex+1;

}

else if(e.keyCode=='40'){

gamey=gamey+1;

}

if(e.keyCode=='32'){

st();

}

}

//清空画布

c.width=w;

c.height=h;

bk();

game(gamex,gamey);

drss();

stsup();

dels();

},10);

</script>

天学习了html5里面的canvas(画布),canvas是一个矩形区域的画布,可以用javascript直接在上面画画,控制上面的元素,他拥有很多的绘图路径,矩形,圆形,字符以及添加图像的方法,它使得页面更加丰富多彩。

下面来看看怎么使用这个神奇的标签。

它在html页面里面是这样的样子,可以直接在上面设置画布的大小,边框等属性

这里提一下,最好在javascript里面设置canvas的宽高,也不要通过css设置canvas宽高,因为使用css来设置,画布的实际大小为(css设置的值)/(js设置的值)倍。

下面正式开始画画了。

第一步:拿到canvas标签,同时设置他的属性

然后就可以第二步拿到canvas的上下文,并且选择2D/3D画图

准备好了就可以开始画画了,我们先来画线吧

可以想象拿着一支笔,先把笔尖移到开始绘画的点,然后开始移动笔。

不过现在的线条还看不见,现在只是有个印,我们还需要让他显现出来。

那么如果我想把他再把它闭合起来并且有填充的颜色。除了手动闭合还可以用到closePath来自动闭合,填充则用fill方法了。

记住:先把路径画好了才可以去描边,填充,不然就会是在用想象力画画,纸上面是不会显示的。

下面再来画个表格

以上就是最基础的画图操作啦,如果有什么疑问或者建议可以在下方评论,喜欢小编的文章就给个关注啦~~