theme: cyanosis
持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第 6 天,点击查看活动详情
开篇前言
在掘金认识我的都知道,我主要是研究 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 样式]----
<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 结构]----
<div class="wrapper">
<div id="paper" class="box"></div>
<span class="leabel">折线: Polyline</span>
</div>
在 script
标签下书写 js 脚本
, 使用方式也比较简单。通过 zrender.init
来关联 dom 节点进行初始化,获取渲染对象。如何创建绘制对象,添加到渲染对象中即可。如下是折线 Polyline
的的绘制效果,可以看出 ZRender
默认的坐标系是以 dom 节点
左上角为原点,向左和下方为正方向的直角坐标系,这也是屏幕渲染中最常用的坐标系:
Polyline
通过 shape.points
属性提供点数组,将点依次连接进行显示:
---->[js 脚本]----
<script>
const render = zrender.init(document.getElementById('paper'))
const stokeStyle = {
stroke: 'red',
lineWidth: 1,
fill: null,
};
const polyline = new zrender.Polyline({
shape: {
points: [
[0, 50],
[10, 60,],
[20, 40,],
[30, 80,],
[40, 20,],
[50, 50,],
[60, 40,],
[100, 40,],
]
},
style: stokeStyle
})
render.add(polyline)
</script>
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