高性能渲染——详解Html Canvas的优势与性能

葡萄城技术团队
葡萄城官方账号
博客专家认证
2023-11-01 09:16:43

本文由葡萄城技术团队原创并首发。转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。

一、什么是Canvas

想必学习前端的同学们对Canvas 都不陌生,它是 HTML5 新增的“画布”元素,可以使用JavaScript来绘制图形。

Canvas元素是在HTML5中新增的标签用于在网页实时生成图像,并且可以操作图像内容,基本上它是一个可以用JavaScript操作的位图(bitmap)。Canvas 由一个可绘制区域HTML代码中的属性定义决定高度和宽度。JavaScript代码可以访问该区域,通过一套完整的绘图功能的API生成动态的图形。

二. 引入Canvas的重要性

HTML5 在 2012 年已形成了稳定的版本,在此之前很长一段时间,开发者们绘制图形选择的方案更多是SVG来实现。SVG使用XML来定义图形,就像使用HTML标签一样来控制元素的排布,SVG的本质就是一个DOM元素。当图形内容太过丰富后,性能和内存上就会大打折扣。一旦涉及频繁的图片绘制场景,这个实现对于用户的体验将是毁灭性的。

渲染动画的基本原理,无非是反复地擦除和重绘。为了动画的流畅,留给开发者渲染一帧的时间,只有短短的 16.67ms。在这16.67ms中,我不仅需要处理一些绘制逻辑,计算每个对象的位置、状态,还需要把它们都画出来。如果消耗的时间稍稍多了一些,用户就会感受到“卡顿”。所以,在编写动画时,开发者们无时无刻不担忧着动画的性能,唯恐渲染的耗时过长。

在现代 Web 开发中,开发者们更多的会借助 Canvas 提供的API去绘制上下文,可以自由绘制各种2D和3D图形,创建富有视觉冲击力的游戏场景和角色。Canvas的使用可以使得游戏能够实现流畅的动态效果和用户交互。无论是简单的小游戏还是复杂的游戏引擎,Canvas 都被广泛应用。

下面是做的一个简单的对比试验,可以很明显感受到两者的差距,分别使用SVG和Canvas绘制一个包含着100w个圆形的500*500的图片,根据耗时计算对比,Canvas耗费的时间几乎只有SVG的一半:

三. 计算与渲染

把动画的一帧渲染出来,需要经过以下步骤:

  1. 计算:处理网页渲染逻辑,计算每个对象的状态和位置。
  2. 渲染:真正把对象绘制出来。
  3. JavaScript 调用 DOM API(包括 Canvas API)以进行渲染。
  4. 浏览器(通常是另一个渲染线程)把渲染后的结果呈现在屏幕上的过程。

之前提到过,在动画设计和开发中,每帧只有16.67毫秒的时间用于渲染。这个数值是通过计算每秒60帧得出的平均每帧渲染时间。实际上,并不是所有设备都能够稳定地达到60FPS。因此,为了确保在不同设备上实现一致性的动画效果,最好将每帧的渲染时间控制在10毫秒以内。

大家都知道,通常情况下,渲染的开销远大于计算(相差3~4个量级)。除非使用了一些时间复杂度很高的算法,否则不需要过于深入优化计算环节。Canvas的渲染是在JavaScript引擎中执行绘制逻辑,通过构建画布在内存中,并遍历所有像素点的颜色,最终输出到屏幕上。这种强大的功能可能会增加学习成本,但如今仍然有很多开发者选择和接受Canvas,这要归功于Canvas最大的优势:渲染性能的出色表现。

四. Canvas渲染性能优势

当谈论图形渲染技术时,就不得不提到DOM驻留模式和Canvas快速模式。

DOM驻留模式

DOM驻留模式是一种基于文档对象模型(DOM)的渲染技术。在DOM驻留模式下,页面的布局和样式是由DOM树来掌管的。当页面需要更新时,浏览器会重新计算布局和样式并重新渲染。此模式非常灵活,特别适用于处理动态页面交互和多样化的样式控制。然而,由于需要频繁地重新计算布局和样式,对于复杂的图形渲染任务来说,性能开销相对较高。

Canvas快速模式

Canvas快速模式利用HTML5的Canvas元素进行图形渲染。在这种模式下,开发者可以使用Canvas提供的2D或3D绘图API直接在画布上绘制图形。相比于DOM驻留模式,Canvas快速模式更加高效。它不关心页面的布局和样式,而是在需要时只重绘受影响的部分。这样就避免了频繁的布局和样式计算,提高了渲染性能。

  1. 分层提高Canvas性能

开发者们通过分析大量实际场景,总结出一套可以进一步提升Canvas性能的策略,即对变化较少和变化较多的内容进行分开渲染。这种策略就是所谓的分层Canvas。它能够显著降低完全没有必要的渲染性能开销。分层渲染的思想被广泛应用于各种图形相关的领域,从古老的皮影戏、套色印刷术,到现代电影/游戏工业以及虚拟现实领域等等。而分层Canvas只是分层渲染思想在Canvas动画上的一个基础应用。

分层Canvas的核心理念是,动态页面中的每种元素(层)对于渲染频率的需求是不同的。对于许多金融会计等大数据行业的从业者来说,主要数据内容的变化频率和幅度较大(他们通常面临数据变动和频繁计算),而背景表格样式的变化频率或幅度相对较小(基本不变,或者变化缓慢,或者仅在特定时机变化)。因此,需要频繁更新和重绘数据,但对于背景,可能只需要绘制一次,或者每隔200毫秒才重绘一次,而没有必要每16毫秒就重绘一次。

  1. 视野之外的绘制

在许多情况下,Canvas 仅仅作为数据展示页面的一部分,充当着一个“窗口”的角色。如果在每次数据更新时,都将所有数据完全绘制到 Canvas 上,很可能会出现大量内容绘制到Canvas 范围之外的情况。虽然调用了绘制 API,但实际上并没有产生任何效果。

因此,判断对象是否位于 Canvas 范围内需要进行额外的计算(例如,需要通过对游戏角色的全局模型矩阵求逆来得出对象的世界坐标,这是一项相对耗时的操作),同时也会增加代码的复杂性。因此,关键是是否需要这样做。

通过在本地代码中进行测试,比较了在视野内和视野外分别绘制100万个圆的耗时。在视野内绘制耗时8936ms,而在视野外绘制耗时2540ms。考虑到计算和绘制之间的耗时差距在3~4个数量级,因此通过计算来判断并避免绘制视野外的内容是一种非常有效的方法。

五. Canvas的应用

之前探讨了SVG和Canvas的绘制性能差异以及Canvas常见的优化方法。知道,对于使用快速模式渲染的Canvas来说,浏览器的每次重绘都是由代码驱动的,无须进行多层解析,因此它的速度非常快。除了速度快之外,Canvas的灵活性也显著优于DOM。可以通过代码精确控制何时以及如何绘制出期望的效果。

在资源消耗方面,DOM的驻留模式意味着场景中的每一个新增元素都会导致额外的内存消耗,而Canvas则没有这个问题。这种差异在页面元素数量增多时尤为明显。

在Canvas出现之前,前端渲染表格只能通过构建复杂的DOM来实现。然而,这种方式会导致浏览器性能成为Web应用的瓶颈,许多开发人员因此放弃了在浏览器上实现电子表格的想法。

Canvas出现后,其快速模式带来的出色性能优势成为了一大亮点,大量、复杂的DOM渲染处理所带来的性能问题因此有了解决之道。

回到电子表格的应用场景,现在已经出现了使用Canvas绘制画布的表格组件。这类组件在渲染数据层时无须重复创建和销毁DOM元素,而且在画布的绘制过程中受到的限制也比DOM元素渲染更少。其中,葡萄城公司的纯前端表格控件——SpreadJS就用到了Canvas实现表格绘制,除了表格之外,Canvas也为数字孪生可视化大屏、页面游戏等应用场景带来了变革(如下图所示)。

六、总结

本文通过介绍Canvas的原理、Canvas的重要性、Canvas在计算与渲染上的作用、Canvas渲染性能优势和Canvas的应用这五个部分,全面而系统地阐述了HTML Canvas在高性能渲染方面的相关知识和技巧。希望读者通过阅读本文能够深入了解Canvas的基本原理和特性,认识到Canvas在Web开发中的重要性,并掌握Canvas在计算与渲染上的作用。

七. 参考文章

《什么是canvas?有什么用?》黑马程序员

《Canvas最佳实践(性能篇)》

《HTML界的“苏炳添”——详解Canvas优越性能和实际应用》

扩展链接:

Redis从入门到实践

一节课带你搞懂数据库事务!

Chrome开发者工具使用教程

如何在前端系统中使用甘特图

窗口函数大揭秘!轻松计算数据累计占比,玩转数据分析的绝佳利器

探秘移动端BI:发展历程与应用前景解析

...全文
907 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复
第1章 Android体系与系统架构 1 1.1 Google生态系统 2 1.2 Android系统架构 2 1.2.1 Linux 3 1.2.2 Dalvik与ART 3 1.2.3 Framework 3 1.2.4 Standard libraries 4 1.2.5 Application 4 1.3 Android App组件架构 4 1.3.1 Android四大组件如何协同工作 5 1.3.2 应用运行上下文对象 5 1.4 Android系统源代码目录与系统目录 6 1.4.1 Android系统源代码目录 6 1.4.2 Android系统目录 8 1.4.3 Android App文件目录 11 第2章 Android开发工具新接触 13 2.1 Android开发IDE介绍 14 2.1.1 Android Studio初体验 14 2.1.2 Android Studio配置 15 2.2 Android Studio高级使用技巧 19 2.2.1 更新SDK 20 2.2.2 Android Studio常用界面 21 2.2.3 导入Android Studio工程 23 2.3 ADB命令使用技巧 24 2.3.1 ADB基础 24 2.3.2 ADB常用命令 25 2.3.3 ADB命令来源 29 2.4 模拟器使用与配置 29 第3章 Android控件架构与自定义控件详解 32 3.1 Android控件架构 33 3.2 View的测量 34 3.3 View的绘制 37 3.4 View Group的测量 38 3.5 View Group的绘制 39 3.6 自定义View 39 3.6.1 对现有控件进行拓展 40 3.6.2 创建复合控件 43 3.6.3 重写View来实现全新的控件 51 3.7 自定义View Group 54 3.8 事件拦截机制分析 59 第4章 List View使用技巧 65 4.1 List View常用优化技巧 66 4.1.1 使用View Holder模式提高效率 66 4.1.2 设置项目间分隔线 68 4.1.3 隐藏List View的滚动条 68 4.1.4 取消List View的Item点击效果 68 4.1.5 设置List View需要显示在第几项 69 4.1.6 动态修改List View 69 4.1.7 遍历List View中的所有Item 71 4.1.8 处理空List View 71 4.1.9 List View滑动监听 72 4.2 List View常用拓展 74 4.2.1 具有弹性的List View 75 4.2.2 自动显示、隐藏布局的ListV iew 76 4.2.3 聊天List View 79 4.2.4 动态改变List View布局 85 第5章 Android Scroll分析 87 5.1 滑动效果是如何产生的 88 5.1.1 Android坐标系 88 5.1.2 视图坐标系 88 5.1.3 触控事件——MotionEvent 89 5.2 实现滑动的七种方法 91 5.2.1 layout方法 92 5.2.2 offset Left And Right()与offset Top And Bottom() 93 5.2.3 Layout Params 93 5.2.4 scroll To与scrollBy 94 5.2.5 Scroller 96 5.2.6 属性动画 98 5.2.7 View Drag Helper 98 第6章 Android绘图机制与处理技巧 106 6.1 屏幕的尺寸信息 107 6.1.1 屏幕参数 107 6.1.2 系统屏幕密度 107 6.1.3 独立像素密度dp 107 6.1.4 单位转换 108 6.22D绘图基础 110 6.3 Android XML绘图 113 6.3.1 Bitmap 113 6.3.2 Shape 113 6.3.3 Layer 115 6.3.4 Selector 116 6.4 Android绘图技巧 117 6.4.1 Canvas 117 6.4.2 Layer图层 121 6.5 Android图像处理之色彩特效处理 122 6.5.1 色彩矩阵分析 122 6.5.2 Android颜色矩阵——ColorMatrix 128 6.5.3 常用图像颜色矩阵处理效果 131 6.5.4 像素点分析 134 6.5.5 常用图像像素点处理效果 135 6.6 Android图像处理之图形特效处理 137 6.6.1 Android变形矩阵——Matrix 137 6.6.2 像素块分析 142 6.7 Android图像处理之画笔特效处理 145 6.7.1 Porter Duff Xfermode 145 6.7.2 Shader 149 6.7.3 Path Effect 153 6.8 View之孪生兄弟——SurfaceView 155 6.8.1 Surface View与View的区别 155 6.8.2 Surface View的使用 156 6.8.3 Surface View实例 159 第7章 Android动画机制与使用技巧 162 7.1 Android View动画框架 163 7.1.1 透明度动画 163 7.1.2 旋转动画 163 7.1.3 位移动画 164 7.1.4 缩放动画 164 7.1.5 动画集合 164 7.2 Android属性动画分析 165 7.2.1 ObjectAnimator 166 7.2.2 PropertyValuesHolder 168 7.2.3 ValueAnimator 168 7.2.4 动画事件的监听 168 7.2.5 Animator Set 169 7.2.6 在XML中使用属性动画 170 7.2.7 View的animate方法 170 7.3 Android布局动画 171 7.4 Interpolators(插值器) 171 7.5 自定义动画 172 7.6 Android 5.X SVG矢量动画机制 175 7.6.1 <path>标签 175 7.6.2 SVG常用指令 176 7.6.3 SVG编辑器 177 7.6.4 Android中使用SVG 177 7.6.5 SVG动画实例 181 7.7 Android动画特效 188 7.7.1 灵动菜单 188 7.7.2 计时器动画 190 7.7.3 下拉展开动画 191 第8章 Activity与Activity调用栈分析 195 8.1 Activity 196 8.1.1 起源 196 8.1.2 Activity形态 196 8.1.3 生命周期 196 8.2 Android任务栈简介 200 8.3 Android Mainifest启动模式 200 8.3.1 standard 201 8.3.2 single Top 201 8.3.3 single Task 201 8.3.4 single Instance 202 8.4 Intent Flag启动模式 203 8.5 清空任务栈 203 8.6 Activity任务栈使用 204 第9章 Android系统信息与安全机制 205 9.1 Android系统信息获取 206 9.1.1 android.os.Build 206 9.1.2 System Property 207 9.1.3 Android系统信息实例 208 9.2 Android Apk应用信息获取之Package Manager 209 9.2.1 Package Manager 210 9.3 Android Apk应用信息获取之Activity Manager 215 9.4 解析Packages.xml获取系统信息 218 9.5 Android安全机制 220 9.5.1 Android安全机制简介 220 9.5.2 Android系统安全隐患 222 9.5.3 Android Apk反编译 223 9.5.4 Android Apk加密 226 第10章 Android性能优化 227 10.1 布局优化 228 10.1.1 Android UI渲染机制 228 10.1.2 避免Overdraw 229 10.1.3 优化布局层级 229 10.1.4 避免嵌套过多无用布局 229 10.1.5 Hierarchy Viewer 234 10.2 内存优化 236 10.2.1 什么是内存 236 10.2.2 获取Android系统内存信息 237 10.2.3 内存回收 238 10.2.4 内存优化实例 238 10.3 Lint工具 240 10.4 使用Android Studio的Memory Monitor工具 240 10.5 使用Trace View工具优化App性能 241 10.5.1 生成Trace View日志的两种方法 241 10.5.2 打开Trace View日志 242 10.5.3 分析Trace View日志 242 10.6 使用MAT工具分析App内存状态 244 10.6.1 生成HPROF文件 244 10.6.2 分析HPROF文件 245 10.7 使用Dumpsys命令分析系统状态 247 第11章 搭建云端服务器 248 11.1 移动后端服务介绍 249 11.2 使用Bmob创建移动后端服务 250 11.2.1 数据服务 251 11.2.2 推送服务 254 第12章 Android 5.X新特性详解 257 12.1 Android 5.X UI设计初步 258 12.1.1 材料的形态模拟 258 12.1.2 更加真实的动画 258 12.1.3 大色块的使用 259 12.2 Material Design主题 260 12.3 Palette 261 12.4 视图与阴影 263 12.5 Tinting和Clipping 265 12.5.1 Tinting(着色) 265 12.5.2 Clipping(裁剪) 267 12.6 列表与卡片 269 12.6.1 Recycler View 269 12.6.2 Card View 275 12.7 Activity过渡动画 276 12.8 Material Design 动画效果 283 12.8.1 Ripple效果 283 12.8.2 Circular Reveal 285 12.8.3 View state changes Animation 288 12.9 Toolbar 293 12.10 Notification 296 12.10.1 基本的Notification 297 12.10.2 折叠式Notification 298 12.10.3 悬挂式Notification 300 12.10.4 显示等级的Notification 301 第13章 Android实例提高 303 13.1 移动迷宫——拼图游戏 304 13.1.1 准备工作 305 13.1.2 初始界面 307 13.1.3 拼图界面 312 13.1.4 效果预览与功能进阶 324 13.2 魔幻矩阵——2048325 13.2.12048概述 325 13.2.22048游戏分析 326 13.2.32048初始化工作 327 13.2.4 小方块设计 328 13.2.5 全局设置 330 13.2.6 游戏面板设计 332 13.2.7 主程序设计 340 13.2.8 功能进阶 341 13.3 实战经验总结 342

87,924

社区成员

发帖
与我相关
我的任务
社区描述
Web 开发 JavaScript
社区管理员
  • JavaScript
  • 无·法
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧