theme: cyanosis
持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第 7 天,点击查看活动详情
开篇前言
在掘金认识我的都知道,我主要是研究 Flutter
的。其实我一直希望开发出一套好用的 Flutter
的图表库,但是期间遇到了一些瓶颈。当我偶然知道 echarts
底层是由 ZRender
引擎渲染时,内心是非常激动的。无论是简单的统计图,还是复杂的雷达图、地图、关系图,本质上都是通过 ZRender
引擎渲染绘制的。
ZRender
封装了前端 canvas
的绘制逻辑,通过上层的接口去操作底层的绘制功能。从而屏蔽不同环境的差异性,提供统一的访问方式,并提供更高级的图形元素的绘制功能,方便使用者的调度,这都是封装的特点。
所以我悟了,相比于 图表库
这种复杂上层建筑,在起步阶段时,一个好的引擎作为底层基础是必不可少的。想打造一个像 echarts
这样几乎完美的图表库,在短时间内是不可能凭空实现的。所以准备研究一下 ZRender
,体会一下其中的设计思想、结构思路和逻辑实现,先打造一个符合 Flutter
框架的二维绘图引擎库 render2d
。这点对于绘制小能手的我感觉还是有些希望的。
所以本系列文章将作为对前端的 ZRender
引擎研究的探索记录。我对 web 前端的知识并不是非常精通,但对于前端的 Canvas
绘制还是略知一二的,借此可能还会巩固一些小前端的知识。
1. ZRender 和基础图形元素介绍
Flutter
中对于绘制封装了 Canvas
、 Paint
、Path
、Matrix4
等类型,并且有自身的 Animation
动画机制。 相比而言,Html
的绘制显得更加原始一些,面向过程的味道更浓,这也是封装一个绘制引擎的必要性。 ZRender
的封装感觉要比 Flutter
绘制系统要高一层级,它封装了很多基础设施,让绘制对于使用者而言更加简易。所以有必要学习一下,它山之石可以攻玉。
ZRender
是一个开源项目,地址在 【ecomfe/zrender】,可以将其 clone
到本地,方便查看源码。
对于绘制的封装而言,基础图形元素是必不可少的,以后简称为 图元
。他们被定义在 graphic
文件夹中,其中 Displayable
是图元比较顶层的抽象。在 shape
文件夹中定义了一些基础图形,它们是 echarts
图表展示的基础。
所以在刚接触 ZRender
时,了解这些图元的使用是一个比较好的切入点。本文先从一些简单的图形元素绘制进行体验,了解 ZRender
的基本使用。
2. ZRender 的使用
作为一个 js 的库,引入的方式大同小异。这里先通过最原始的方式体验一下 zrender
, 先不通过前端框架集成。在下载的源码后,在 dist
文件夹中可以得到库文件:
对于简单的集成体验,使用 script
标签引入库即可:
对于图元的绘制测试,将使用如下的展示方式:在 100*100
的虚线框内部是绘制内容,框下是标题信息。所以先来准备一些结构和样式。如下所示,这些非常基础,就不介绍了:
css ---->[css 样式]---- <style> .wrapper { display: flex; flex-direction: column; align-items: center; } .box { width: 100px; height: 100px; border: 2px dashed; } .leabel { margin-top: 5px; font-size: 14px; font-weight: bold; color: gray; } </style>
布局结构上是通过 flex
布局维护的上下结构:
```html ---->[html 结构]----
```
在 script
标签下书写 js 脚本
, 使用方式也比较简单。通过 zrender.init
来关联 dom 节点进行初始化,获取渲染对象。如何创建绘制对象,添加到渲染对象中即可。如下是折线 Polyline
的的绘制效果,可以看出 ZRender
默认的坐标系是以 dom 节点
左上角为原点,向左和下方为正方向的直角坐标系,这也是屏幕渲染中最常用的坐标系:
Polyline
通过 shape.points
属性提供点数组,将点依次连接进行显示:
``` ---->[js 脚本]----
```
3.直线、矩形、圆形的绘制
这三个图形,是基础中的基础,在 ZRender
中分别通过 Line
、Rect
、Circle
绘制。由于基本流程是相同的,下面的绘制体验中,只贴出核心的图元对象创建的代码:
直线通过 shape
属性的 x1
、y1
、x2
、y2
指定两个坐标,进行连线:
const line = new zrender.Line({ shape: { x1: 0, y1: 0, x2: 100, y2: 100, }, style: stokeStyle })
矩形 Rect : 通过左上角坐标 (x,y)
和宽高 width
、 height
确定形状,另外可以使用 shape.r
属性指定四周圆角:
``` const rect = new zrender.Rect({ shape: { x: 10, y: 10, width: 80, height: 80, }, style: stokeStyle })
const rrect = new zrender.Rect({ shape: { x: 25, y: 25, r: [5,10,5,10], width: 50, height: 50, }, style: stokeStyle }) ```
圆形 Circle : 通过圆心坐标 (cx,cy)
和半径 r
、 height
确定形状:
const circle = new zrender.Circle({ shape: { cx: 50, cy: 50, r: 50, }, style: stokeStyle })
4. 圆弧、椭圆、贝塞尔曲线
下面来看一组曲线:圆弧、椭圆、贝塞尔曲线分别由 Arc
、Ellipse
、BezierCurve
绘制。圆弧就是圆上的一段弧线,通过指定 startAngle
和 endAngle
截取:
const arc = new zrender.Arc({ shape: { cx: 50, cy: 50, r: 40, startAngle: 0, endAngle: 135 * Math.PI / 180, }, style: stokeStyle })
椭圆 Ellipse
通过中心点 (cx,cy)
和横纵半轴长 rx
、ry
确定:
const ellipse = new zrender.Ellipse({ shape: { cx: 50, cy: 50, rx: 50, ry: 30, }, style: stokeStyle })
贝塞尔曲线 BezierCurve
在绘制界可谓老生常谈的知识了。这里的 BezierCurve
可以绘制二次和三次贝塞尔曲线。如下是一段二次贝塞尔曲线:参数包括 起点 (x1,x2)
、控制点1 (cpx1,cpy1)
、终点 (x2,y2)
const bezierCurve2 = new zrender.BezierCurve({ shape: { x1: 30, y1: 20, cpx1: 70, cpy1: 10, x2: 80, y2: 40, }, style: stokeStyle })
另外,如果指定 控制点2 (cpx2,cpy2)
就会绘制三次贝塞尔曲线:
const bezierCurve3 = new zrender.BezierCurve({ shape: { x1: 30, y1: 20, cpx1: 50, cpy1: 10, cpx2: 80, cpy2: 20, x2: 80, y2: 40, }, style: stokeStyle })
关于贝塞尔曲线,在 《【Flutter 绘制番外】svg 终篇 - 路径指令》 一文中有所介绍,结合其中的图来看更好理解一些:
5. 文字、图片的简单绘制
另外,绘制过程中还有文字和图片这两个非常重要的部分,通过 Text
和 Image
绘制。 文字的样式非常多,属性在 style 中配置,基本上和 css
的属性是类似的,这里先简单体验一下:
const text = new zrender.Text({ style: { text : 'ZRender', fontSize: 20, x:10, y:40 } })
图片通过 Image
进行展示,属性也在 style
中配置:
const text = new zrender.Image({ style: { image : '../assets/icon_head.webp', x:10, y:10, with:80, height:80, } })
这上面的 9 种是最基础的图形元素,这里只是简单的绘制体验,在 zrender 官网文档 中有对各种图形的详细属性介绍,感兴趣的可以自己参阅。下一篇,将介绍一下其他的不太常用的图元,并基于 Vue
框架来整合这些绘制样例。那本文就到这里,谢谢观看 ~
@张风捷特烈 2022.10.21 未允禁转
我的 公众号: 编程之王
我的 github 主页
: toly1994328