文章作者:萌萌哒的邱邱邱邱
原始链接:https://qiuruolin.github.io/2019/05/20/echarts-1/
由于echarts是基于zrender进行实现的,所以要解读echarts源码,首先要对zrender有大致的了解,在这篇文章中,我将对zrender的整体结构进行大致的解读。
zrender是canvas的一个类库,也就是说zrender是基于canvas实现的,canvas API可以参考:W3CSchool Canvas 参考手册
在后续的解读中,我们会介绍zrender使用canvas api 的位置及用途。
文件夹:
全局的文件:
zrender采用了MVC封装,M为Model数据层,V为View视图层,C为Controller控制层:
处于graphic文件夹下,zrender定义了一系列图形,供外界调用,包括圆形、矩形、心形、扇形、多边形、折线等,echarts通过调用zrender定义好的图形,可以很便捷地完成图表渲染。
Displayable.js为Path、Text等的基类,继承自Element,定义了setStyle、useStyle等方法,
文本,继承自Displayable,调用了helper/text.js中的renderText方法进行绘制。主要代码如下:
export function renderText(hostEl, ctx, text, style, rect, prevEl) {
style.rich
? renderRichText(hostEl, ctx, text, style, rect, prevEl)
: renderPlainText(hostEl, ctx, text, style, rect, prevEl);
}
文本分为富文本以及普通文本进行分别渲染,它们均通过调用canvas的ctx.fillText或ctx.strokeText 等api进行文本渲染,具体实现可以查看helper/text.js文件。
图形的样式文件,定义了基本的样式属性,以及样式set、clone以及判断等方法。
path为图形的基类,继承自Displayable,定义了buildPath、getBoundingRect、setShape等方法,其包含this._style属性即为Style对象实例。
shape文件下存放着zrender定义的图形文件,扩展自Path。
圆形,通过调用Path.extend方法进行扩展,重写了buildPath方法,buildPath调用了canvas api:ctx.arc进行圆形的绘制,主要实现代码如下:
buildPath: function (ctx, shape, inBundle) {
if (inBundle) {
ctx.moveTo(shape.cx + shape.r, shape.cy);
}
ctx.arc(shape.cx, shape.cy, shape.r, 0, Math.PI * 2, true);
}
弧形,通过调用Path.extend方法进行扩展,重写了buildPath方法,buildPath调用了canvas api:ctx.arc进行弧形的绘制,主要实现代码如下:
buildPath: function (ctx, shape) {
var x = shape.cx;
var y = shape.cy;
var r = Math.max(shape.r, 0);
var startAngle = shape.startAngle;
var endAngle = shape.endAngle;
var clockwise = shape.clockwise;
var unitX = Math.cos(startAngle);
var unitY = Math.sin(startAngle);
ctx.moveTo(unitX * r + x, unitY * r + y);
ctx.arc(x, y, r, startAngle, endAngle, !clockwise);
}
心形❤️,通过调用Path.extend方法进行扩展,重写了buildPath方法,buildPath调用了canvas api:ctx.bezierCurveTo进行弧形的绘制,主要实现代码如下:
buildPath: function (ctx, shape) {
var x = shape.cx;
var y = shape.cy;
var a = shape.width;
var b = shape.height;
ctx.moveTo(x, y);
ctx.bezierCurveTo(
x + a / 2, y - b * 2 / 3,
x + a * 2, y + b / 3,
x, y + b
);
ctx.bezierCurveTo(
x - a * 2, y + b / 3,
x - a / 2, y - b * 2 / 3,
x, y
);
}
bezierCurveTo(控制点1x坐标, 控制点1y坐标, 控制点2x坐标, 控制点2y坐标, 结束点x坐标, 结束点y坐标)
三次被塞尔曲线绘制:
具体绘制图如下:
同理,我们可以绘制出左半边心形:
水滴形状,通过调用Path.extend方法进行扩展,重写了buildPath方法,buildPath调用了canvas api:ctx.bezierCurveTo进行弧形的绘制,贝塞尔曲线的绘制过程同心形绘制原理,主要实现代码如下:
buildPath: function (ctx, shape) {
var x = shape.cx;
var y = shape.cy;
var a = shape.width;
var b = shape.height;
ctx.moveTo(x, y + a);
ctx.bezierCurveTo(
x + a,
y + a,
x + a * 3 / 2,
y - a / 3,
x,
y - b
);
ctx.bezierCurveTo(
x - a * 3 / 2,
y - a / 3,
x - a,
y + a,
x,
y + a
);
ctx.closePath();
}
椭圆,通过调用Path.extend方法进行扩展,重写了buildPath方法,buildPath调用了canvas api:ctx.bezierCurveTo进行弧形的绘制,贝塞尔曲线的绘制过程同心形绘制原理,主要实现代码如下:
buildPath: function (ctx, shape) {
var k = 0.5522848;
var x = shape.cx;
var y = shape.cy;
var a = shape.rx;
var b = shape.ry;
var ox = a * k; // 水平控制点偏移量
var oy = b * k; // 垂直控制点偏移量
// 从椭圆的左端点开始顺时针绘制四条三次贝塞尔曲线
ctx.moveTo(x - a, y);
ctx.bezierCurveTo(x - a, y - oy, x - ox, y - b, x, y - b);
ctx.bezierCurveTo(x + ox, y - b, x + a, y - oy, x + a, y);
ctx.bezierCurveTo(x + a, y + oy, x + ox, y + b, x, y + b);
ctx.bezierCurveTo(x - ox, y + b, x - a, y + oy, x - a, y);
ctx.closePath();
}
扇形,通过调用Path.extend方法进行扩展,重写了buildPath方法,buildPath调用了canvas api:ctx.arc以及arc.lineTo进行圆形的绘制,主要实现代码如下:
buildPath: function (ctx, shape) {
var x = shape.cx;
var y = shape.cy;
var r0 = Math.max(shape.r0 || 0, 0);
var r = Math.max(shape.r, 0);
var startAngle = shape.startAngle;
var endAngle = shape.endAngle;
var clockwise = shape.clockwise;
var unitX = Math.cos(startAngle);
var unitY = Math.sin(startAngle);
ctx.moveTo(unitX * r0 + x, unitY * r0 + y);
ctx.lineTo(unitX * r + x, unitY * r + y);
ctx.arc(x, y, r, startAngle, endAngle, !clockwise);
ctx.lineTo(
Math.cos(endAngle) * r0 + x,
Math.sin(endAngle) * r0 + y
);
if (r0 !== 0) {
ctx.arc(x, y, r0, endAngle, startAngle, clockwise);
}
ctx.closePath();
}
zrender还定义了Rect矩形、Isogon正多边形、Line直线、Polygon多边形、Polyline折线、Ring圆环、Rose玫瑰线、Star n角星等图形,其实现过程基本与上述图形上类似,都是基于canvas的lineTo、arc、bezierCurveTo等api进行绘制的,这边就不做一一介绍了。
zrender中封装了很多工具,在后续echarts源码解读中,我们可以看到echarts是基于zrender进行开发的。