从图形到像素:前端图形编程技术概览

2019 年 3 月 06 日

从图形到像素:前端图形编程技术概览

图形是人与人之间传递信息的媒介,直观性远胜于口头语言和书面语言。4000多年前,古巴比伦人在石块上绘制建筑物的平面图;2000多年前,古希腊人用图形表达建筑思想,而与其相关的数学直到文艺复兴时期才开始完善。


—— 摘自《交互式计算机图形学(第七版)》


将以上的理念带入到计算机领域,图形是计算机向用户传递信息的主要媒介。不论是 26 个英文字母构成的代码还是枯燥的二进制,在直观性上远不能比得上图形。这也是前端相对于其他领域最显著的特征。


我入行前端的过程颇有些曲折,读书期间主攻的方向是当时正热的 Android 开发,拿到的第一个 offer 是盛大游戏的测试实习生。可惜盛大要求每周五天全勤,而当时我正在写毕业论文,时间上没法保证,很遗憾地拒掉了。第二个 offer 是 SAP 上海研究院 BI 部门的前端实习生,有趣的是,面试的过程中没有被问及任何关于前端的东西,反而着重讨论了 Android 的 UI 适配问题。最终靠着 Android 开发的一点皮毛知识,因缘巧合地成为了一名前端开发者。


在 SAP 参与的项目是基于 SVG 的 charts 图表库,技术选型上使用的是开源的 D3.js。Charts 在完整的 Web 应用中仅仅是作为展示数据的工具,是相对小众的领域,尤其是在如今普及大前端概念的时代背景下更鲜有人讨论。我在实习的半年时间内,没有接触到 AJAX/跨域/CSS 兼容性这些前端“常识”,烂熟于心的是 viewBox/transform/SMIL(用于实现 SVG 动画)等 SVG 图形编程的基本要素。然而尴尬的是参加校招时发现根本没有任何一家公司的前端笔试和面试会涉及这些,导致当时我郁闷地以为怕是入错了行。后来随着工作的深入,我逐渐体会到虽然 charts 与常规前端项目所涉及的知识点略有不同,但实际上两者的差异并非表面看上去那样巨大。


举个比较常见的例子,SVG 与 CSS 存在同名属性 transform,用法基本一致(SVG 不支持 3D 变换),支持 translate/scale 等快捷写法,也支持 matrix 矩阵。CSStransform 的默认变换原点为 HTML 节点自身的中心,即 transform-origin:center center。


SVG 中并不存在 transform-origin 属性,其变换的的原点始终为 SVG 节点自身的左上角。其实 CSS 的 transform-origin 默认为 center center 是考虑到日常开发中所接触的 transform 大多以中心点均为原点,如果将其赋值为 0 0 则与 SVG 等同。


transform-origin 很大程度上简化了 transform 的复杂度,但本质上 CSS 的 transform 使用的是与 SVG 相同的坐标体系。事实上,CSS 的 transform 规范本身便是在 SVG 1.1 规范的基础上延展而来。除此之外,常规前端技术领域还存在与 SVG 许多相似的理念,比如 CSS animation/key-frame 与 SMIL、Shadow DOM 与SVG<use>等等。


值得一提的是,D3.js的节点与数据绑定、数据驱动UI的模式与React颇为类似,却比React的诞生早了许多年。


从图形到像素


虽然相对于 CSS,SVG 略显晦涩,但它本身仍然是非常上层的图形编程技术。SVG 是一种描述性语言,编程的主要方式是通过标签和属性的搭配,其语义性侧重功能而非逻辑。开发者需要做的是熟知各个标签和属性的功能,而无需关注底层实现。比如计算机图形学所描述的最小系统仅支持点、线段和三角形这三种基本图元,SVG 一个简单的<circle>标签背后是计算机在基本图元基础上逐个像素的计算逻辑。也就是说,SVG 编程的最小单元是图形而非像素。细节处理能力的不足,以及性能的瓶颈(大量的节点),令 SVG 难以应对复杂的图形应用程序,“面向像素”的图形编程技术-canvas 便成了进一步的选择。


准确地说,canvas 分为两部分:HTML 中的<canvas>标签和渲染上下文(Rendering Context),其中渲染上下文又可分为 2D 渲染上下文和 WebGL 渲染上下文。canvas 2D 在图形的绘制层面可以视为 SVG 的阉割版:去掉了图形,只保留路径(path)。


canvas 2D 渲染的基本图元只有长方形 rect,其他所有图形均是由 path 完成。在 path 的基础上封装了一些常用路径的便捷 API,比如直线 lineTo()、圆弧 arc()、贝塞尔曲线 bezierCurveTo()等等。对于简单图形的绘制 canvas 并不如 SVG 便捷,所以对于数据量较小、结构简单的 charts(比如柱状图、饼图等)SVG 是比 canvas 更好的技术选型。canvas 的强大之处在于两点:


  • 丰富的逻辑表现力。canvas相对底层的API有更大的扩展空间,并且canvas支持操作(保存/恢复)画布的状态,可应对场景多样的图形应用程序;

  • 像素级的处理能力。canvas可以获取和修改每个像素点的色值,实现一些炫酷的视觉效果,比如下图所示的素描风格处理;



从 CSS 到 SVG,前端 UI 脱离了方块(CSS 盒子)的束缚;从 SVG 到 canvas,前端 UI 的表现力深入到像素级。但截止到此也仅仅是在二维世界里打转,前端 UI 急切需要能将其带入到三维世界的“三向箔”。


从二维到三维


WebGL 其实是个“老古董”了,早在 2007 年 Mozilla 和 Opera 浏览器就各自实现了初始版本。其标准的推进也非常迅速,WebGL 1.0 标准规范于 2011 年发布。对比之下,2014 年被正式确认的 HTML5;2015 年发布的 ES6;以及虽然 1999 年就开始制定草案却直至今天仍有部分特性未被确定为标准的 CSS3 们简直就是小鲜肉了。


相对于 canvas 2D,WebGL 不仅仅是只增加了一个 Z 轴,而是更底层的图形编程技术。WebGL 理论上更接近纯粹的计算机图形学,基本图元只包括点、线段和三角形,并且只支持 1 像素宽的线段。像素处理仅仅是 canvas 2D 的一种高级特性,但是对于 WebGL 来说,每一次绘制都是像素级操作。


与 CSS/SVG/canvas 2D 比起来,WebGL 的开发过程是相对枯燥的,没有便捷的绘图和变换 API,每个图形均是向量和矩阵综合运算的结果。但这也正是图形编程独特的魅力。将枯燥的数字和最简单的图元组合为复杂的 UI,这是一种极致的创造乐趣。


WebGL shader 的计算由 GPU 承担,有着比 CPU 更强悍的计算能力,所以 WebGL 最佳的应用场景是数据量庞大、计算密集型程序。目前市场对于 WebGL 应用最广泛的领域包括游戏、地图、WebVR、数据可视化等。


游戏


游戏是一种极致的强交互式应用,受限于浏览器可调用资源的局限性,HTML5 游戏相对于客户端游戏更轻量,但是随着设备硬件性能的提升和浏览器的进化,目前市面上也不乏可媲美端游的大型 HTML5 游戏。在保证图形质量的前提下,游戏引擎最核心的是计算性能,能够调动 GPU 的 WebGL 自然成为了不二之选。


地图


目前较主流的地图厂商如 Google、高德、百度等均推出了矢量的 3D web 地图(搜狗地图的矢量引擎即将推出,敬请期待),高清 3D 地图的数据体量和计算密集度并不亚于游戏。


WebVR


2016 年被称为“VR 元年”,虽然目前 VR 的热门度远不及当初,但并不代表这个领域没有市场,只是回到了一个相对理性和稳定的发展速度上。强调沉浸式体验的 WebVR 对图形的要求非常苛刻,在 VR 视角下 1 像素的锯齿都会影响整体的观感。此外,WebVR 的视角变换灵敏度远甚于鼠标和键盘,用户头部一个微小角度的转动都会触发应用程序大量的计算。综合这些特征,开发 WebVR 应用的技术栈必须具有像素级处理能力以及高性能计算能力,在前端技术领域能够满足这两项要求的仅有 WebGL。


数据可视化


在人工智能几乎遍布街头巷尾的今天,TensorFlow.js 带给了前端开发者一个新的市场和方向。作为前端开发者,尤其是作为一个 WebGL 图形编程的从业者,我看到了人工智能与前端最紧密也是最理性的结合方式:数据可视化。如果试图依靠前端有限的计算能力做深度的机器学习可能有些痴人说梦,但是不论什么时代、何种业务形式,视觉展示都是“刚需”。数据体量和交互场景复杂度的提升也必然推进数据可视化领域的改革,WebGL 必然会取代 SVG 成为复杂数据可视化应用的最佳选择。


与新技术的融合


性能是计算密集型图形编程的应用架构核心要素之一,任何可压榨浏览器性能的技术和模式均可尝试,即便新技术只具备部分可行性,比如 web worker 和 WebAssembly。


web worker 用于实现多线程,并且 worker 线程安全,是前端实现并行计算的最佳也是唯一技术选型。目前浏览器支持度比较理想,几乎成为了 WebGL 应用的基础技术栈。


WebAssembly 正式规范虽然还未发布,但可以确定的是 WebAssembly 能够大幅提升前端的计算性能,计算密集型的图形编程是其最佳的应用场景之一。


工程化


相对于常规前端项目,图形编程应用在工程化实施上更具优势。图形编程是纯粹的客户端渲染并且无 SEO 需求,更利于前后端分离开发和动静资源的分离部署。数据驱动 UI 也更利于单元测试。


总结


传世名画无非是简单的颜料所成,背后是画师们独特的构图思想和创作技法;木结构的中国古建筑得以千年不倒,其精髓不在于木材而是工匠们的榫卯技艺,这些均是用简单原料创造出的艺术品。从 CSS 到 SVG,从 SVG 到 Canvas2D,从 Canvas2D 到 WebGL,前端图形编程技术越来越接近底层,开发者所能使用的“原料”也越来越有限,用最简单的原料实现丰富视觉表现力的过程中必然充满了极致的创造乐趣。


作者简介


周俊鹏,搜狗地图 Web 前端主管,负责 Web 前端团队管理和工程化体系建设工作。主要研究方向为前端工程化、前端图形编程和 Web 应用层架构。


更多内容,请关注前端之巅。



会议推荐


2019 年 6 月,GMTC 全球大前端技术大会 2019 即将到来。小程序、Flutter、移动 AI、工程化、性能优化…大前端的下一站在哪里?点击下图了解更多详情。



2019 年 3 月 06 日 14:264923

评论

发布
暂无评论
发现更多内容

架构师课程第四周 作业

杉松壁

架构师训练营 -- 第四周作业

stardust20

ARTS打卡 第5周

引花眠

ARTS 打卡计划

第四周作业

andy

Go:gsignal,信号大师

陈思敏捷

go golang signal gsignal os.Signal

架构师训练营 - 第四周 - 学习总结

stardust20

极客时间 - 架构师培训 - 4 期作业

Damon

架构师训练营 - 第四课作业 -20200701- 架构演化

👑👑merlan

极客大学架构师训练营

ARTS|Week 5 有效的括号、API和地图

Puran

LeetCode ARTS 打卡计划

消息队列(二)如何保证消息队列的高可用?

奈何花开

Java MQ 消息队列

清华百万年薪架构师,精心编写多线程与高并发实战PDF

互联网架构师小马

Java 程序员 多线程 架构师 多线程与高并发

阿里巴巴的发展史(组织变革+技术变革)

王锟

阿里巴巴

【源码系列】Spring Cloud Eureka

Alex🐒

源码 Spring Cloud Eureka

架构师训练营 - 第 4 课总结 -20200627- 互联网架构设计

👑👑merlan

架构设计 互联网架构

架构师面试题(3)

满山李子

分布式系统设计 - 第四周作业

孙志平

关于编码的一点“思考”

damnever

golang 思考 抽象 分层架构 编码

通过Python来获取北京市乡镇、街道行政区划数据

Puran

Python GIS geopandas QGIS 天地图

SQL运行内幕:从执行原理看调优的本质

arthinking

MySQL 数据库

架构师训练营 -week4 命题作业

J.Spring

极客大学架构师训练营

LeetCode | 6. Valid Parentheses 有效的括号

Puran

算法 LeetCode

使用数据卷管理数据 | Docker 系列

AlwaysBeta

Docker 容器 数据 容器技术

架构师培训营第四周总结

王锟

架构第四周 - 学习总结

J.Spring

极客大学架构师训练营

Week4 学习总结

wyzwlj

极客大学架构师训练营

架构师训练营 - Lesson Week 4

brave heart

极客大学架构师训练营

每周学习总结 - 架构师培训 4 期

Damon

大型互联网公司技术方案与手段浅析

俊俊哥

分布式 高可用 大型软件 高并发 解决方案

一文搞懂 Redis高性能之IO多路复用

flyer0126

redis io 多路复用 高性能

第4周总结

andy

信息的表示与存储-浮点数的运算

引花眠

计算机基础

从图形到像素:前端图形编程技术概览-InfoQ