|
/ 前言 /早期的浏览器并没有提供 2d 绘图功能,许多用到绘图的地方往往使用 flash 完成。随着 html5 标准的普及,svg/canvas 在浏览器中基本不存在兼容性问题了,在 node,小程序环境也能使用 canvas 绘图。各种基于 2d 绘图的应用也开始涌现出来, 比如像 echarts,g2 这样的可视化库, processon 的流程图, 甚至连谷歌文档也改用 canvas 实现了。本文介绍 2d 绘图的基础知识以及一些性能优化手段。/ 基础技术 /目前常见的 web 2d 绘图使用的底层技术主要是 canvas 和 svg, 大多数 2d 渲染引擎都是基于这两种技术,如 zrender、paperjs、raphael.js。webgl 主要用于 3d 渲染, 2d 是 3d 的一个特例,所以 webgl 也可以用来绘制 2d 图形,如 pixijs。这几种技术各有优缺点,一般来说对于偏静态的场景如图表库、图可视化,使用 canvas/svg 差点不大。在数据量较大或动画较多的场景,使用 canvas 在性能上会更有优势。webgl 除了性能优势外,还能做出很多 canvas/svg 没有的特效。svgsvg 是基于 xml 的 2d 矢量绘图技术,具有分辨率无关的优点,缩放时不会模糊。除了提供基本的绘图外,svg 还内置了动画和丰富的滤镜元素。由于 svg 是基于 dom 的,也可以很好地与 react, vue 等框架结合。 canvascanvas 画布是 html5 中新增的元素, 用于提供绘图接口。和 svg 相比, canvas 对像素的掌握更灵活,而且没有 dom,对于大量数据的渲染,性能相比 svg 更好一些。// 用canvas画一个圆const ctx = canvas.getContext('2d')ctx.beginPath()ctx.arc(50, 50, 10, 0, Math.PI * 2)ctx.fillStyle = '#000'ctx.strokeStyle = 'red'ctx.fill()ctx.stroke()webgl使用 webgl 绘制 2d 图形通常做法是将 2d 图形使用三角剖分,再使用 webgl 绘制三角形。简单几何形状如直线、圆、矩形的三角剖分比较容易, 对于复杂形状尤其是带孔洞的三角剖分,则要麻烦的多。还有一种基于 SDF(有向距离场)的方案来绘制一些常见几何形状。这种方案定义点在区域边界外部为正,边界上为 0,边界内为负。通过 sdf 函数,可以判断像素点是否在图形内。圆的 sdf 函数float myCircleSDF( in vec2 p, in float r ) { return length(p)-r;}/ 图形绘制 /在 svg 中除了直接提供常见的图形元素如 rect, circle, polygon 等形状外,还提供了一个万能的path元素,通过 path 指令完成任何形状的绘制。canvas 也提供了类似 path 的 api, 可以和 svg path 实现互相转换,进而实现 svg/canvas 双引擎的支持。canvassvg pathmoveTom, MlineToL, lbeizerCurveToc, C, S, squadraticCurveToQ q T tarc & ellipseA, aclosePathz, Zrect-svg path 绘制一个三角形
使用 canvas 实现ctx.beginPath()ctx.moveTo(0,0)ctx.lineTo(100, 100)ctx.lineTo(0, 100)ctx.closePath()此外现代浏览器支持使用Path2D对象生成绘制路径const path = new Path2D('M 0,0L100,100L0,100Z');ctx.fill(path);/ 事件交互 /如果使用的是 svg 绘图技术,可以像普通 dom 元素一样监听各种事件。而 canvas 只提供了一个画布,无法直接获取事件坐标所在的图形,需要用户自己判断拾取,常见的拾取方式有几何拾取和像素拾取。此外,canvas 2d 提供了isPointInPath api 用于判断点是否在路径内。几何拾取几何拾取是直接基于数学方法判断点的坐标是否在图形内。比如点是否在圆内的,可以计算点到圆心的距离是否小于圆的半径。function isPointInCirlce(cx, cy, r, x, y) { return (x -cx ) ** 2 + (y - cy) ** 2
|
|