背景
Canvas 在图像处理、绘制渲染上有一些得天独厚的劣势。然而当咱们以后展现的内容中在主题内容变动不大的状况下,会有一些小局部内容的变动,在页面刷新或者滚动的时候,一帧中会有很多简单内容元素的图画运算,从新对页面元素绘制会导致 CPU 使用率飙升。
而从新绘制的过程,本质上是一个一直刮白 - 重画的过程。但在屏幕上实现这一系列操作是须要肯定工夫的,而且屏幕上的图形越简单,所花的工夫就越长,咱们肉眼可见的刮白 - 重画操作,在应用过程中就会让就会间接感觉到屏幕的闪动。
重绘带来的性能累赘和闪动的问题,会给使用者带来较差的应用体验。为了更好的优化这个两个问题,呈现了双缓存画布和油画分层的绘制办法。而本节内容咱们也将从电子表格技术登程,为大家揭秘在电子表格技术中双缓存与优化技术的具体利用。
双缓存画布
当初咱们有一幅图须要放在 Canvas 中,应用 drawImage() 办法,有三种写法:
// 将 image 放到指标 canvas 指定地位
void ctx.drawImage(image, dx, dy);
// 将 image 放到指标 canvas 指定地位,指定宽高渲染
void ctx.drawImage(image, dx, dy, dWidth, dHeight);
// 将 image 裁剪之后放到指标 canvas 指定地位,指定宽高渲染
void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
第一种办法只是把图片原样放到 Canvas 中,第二种办法指定宽高就意味着放大或者放大图片后再放进去,第三种是将图片裁剪后再放大或者放大放到 canvas 中,这三种写法操复杂度作顺次减少,性能开销也随之增大。
而如果应用离屏渲染(即咱们所说的双缓存画布),咱们能够事后把图片裁剪成想要的尺寸,而后将该内容保存起来,绘制的时候间接应用第一种写法间接将图片放入 Canvas 中。
// 在离屏 canvas 上绘制
var offscreencanvas = document.createElement('canvas');
// 宽高赋值为想要的图片尺寸
offscreencanvas.width = dWidth;
offscreencanvas.height = dHeight;
// 裁剪
offscreencanvas.getContext('2d').drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
// 在视图 canvas 中绘制
viewcontext.drawImage(canvas, x, y);
双缓存画布技术的外围在于零碎须要在内存中开拓一块与以后画面等大的“逻辑屏幕“。咱们的画图和动画操作都会先作用于这块”逻辑屏幕“中,当一个操作在这块”逻辑屏幕“上实现之后,再把整块”逻辑屏幕“投放到咱们的屏幕上。
(离屏渲染原理示意图)
在这样的过程之下,咱们是无奈看到整个图形在屏幕上的重绘过程,从而解决了闪动问题。就如同看动漫一样,不必双缓存技术,就是画一帧看一帧,必定会卡顿。而用了双缓存技术,会当时把每一帧画好,一直翻动展现进去。
(逐帧动画)
Canvas 为此提供了 OffscreenCanvas 办法,用来构建一个能够脱离屏幕渲染的 canvas 对象,它在窗口环境和 web worker 环境均无效。对于一些渲染,如果创立 Image 再进行渲染,会耗费大量 CPU,但用离屏渲染,实测在高频事件中 CPU 使用率缩小了一倍之多。
油画分层绘制
分层渲染来解决画面动画的思路并不是当初才有的,从非物质文化遗产皮影戏、套色印刷技术,到当初的音影工业等泛滥畛域都有频繁呈现,而这种思维在 Canvas 中也处在基石的位置。
(分层渲染原理示意图)
Canvas 分层的思维是,动画中每种元素,对渲染和动画的要求是不一样的。
用下图举个例子,在这张图片中除了猫自身在静止外,背景以及下方的文字都是静止反复的。
(油画分层机制示意图)
依照分层的逻辑,咱们须要频繁更新绘制的只有最上方的猫咪。这个办法相似油画的绘制,所以也被称为油画分层机制。应用这个办法联合双缓冲技术能够无效的将反复绘制的内容分流到屏幕外的画布上,而后再依据咱们的需要将屏幕外图像渲染到主画布上,省去了频繁生成重复部分的步骤。
技术利用落地
在理论利用中须要在前端对简单内容进行渲染或者解决大量数据时,为了更好地对性能进行优化,当初曾经有很多我的项目理论采纳了 Canvas 的双缓存画布和油画分层技术。咱们在做电子表格技术选型时也思考到了这些问题,在电子表格利用我的项目中,咱们动辄须要解决百万数量级数据内容,这种状况下浏览器对表格内容渲染和数据处理的性能就显得无比重要。
上图是纯前端电子表格中 50000*20=100000 个数据,解决只须要 0.038s。在该纯前端电子表格中,整个绘制引擎依据油画绘制原理,分为主体图层和装璜图层,主题图层将会渲染长久的,不会轻易扭转的元素,例如背景,单元格,表格线等。而装璜图层则会渲染常变性元素,例如抉择框,拖拽框,悬浮成果等。在下图中第一层到第四层都是主体图层的内容,第五层是装璜图层。
除此之外整个的绘制过程并不是从数据层(Model)间接到视图层(View)的。而是依据表格内容的特殊性,实现了依据视图层形态,从数据层组合出一层专属视图层的视图数据(ViewModel),再配合前文提到的双缓存画布绘制机制,实现整个表格按需绘制的需要,并缓存绘制后果,进一步晋升绘制性能。
主体图层不是间接绘制在用户能看到的主画布上,而是绘制在一个看不见的缓存画布上。在须要渲染时,只须要讲缓存画布的内容克隆到主画布上,再附加上装璜图层元素
这样,当表格须要更新时候,比方单元格背景扭转,只须要在克隆缓存画布后重绘对应单元格内容即可。
而当表格向下滚动时,表格滚动完结,须要重绘,主画布会被清空,而后从缓存画布中依据行为上下文进行画布偏移,将偏移后的图层间接绘制在主画布上,随后在主画布上绘制偏移后的残余局部,最初更新缓存。
应用缓存画布和油画分层机制,大大晋升了绘制性能,使整个滚动过程更加晦涩、顺滑。
感觉不错给点个赞吧~ 后续还会为大家带来更多技术揭秘和乏味内容。
转载请注明出处:葡萄城官网,葡萄城为开发者提供业余的开发工具、解决方案和服务,赋能开发者。
l MDN Web Docs:Canvas 离屏渲染
l Wiki 百科:Canvas 介绍
l 从软件架构议论双缓存画布与油画绘制技术公开课
l 纯前端表格控件 SpreadJS