0
点赞
收藏
分享

微信扫一扫

Echarts源码阅读指南

宁静的猫 2022-03-30 阅读 58


文章作者:萌萌哒的邱邱邱邱

前言

由于echarts是基于zrender进行实现的,所以要解读echarts源码,首先要对zrender有大致的了解,在这篇文章中,我将对zrender的整体结构进行大致的解读。

介绍

zrender是canvas的一个类库,也就是说zrender是基于canvas实现的,canvas API可以参考:W3CSchool Canvas 参考手册

在后续的解读中,我们会介绍zrender使用canvas api 的位置及用途。

目录介绍

文件夹:

  • animation 动画有关;
  • contain 包含判断;
  • container Group.js 元素组的概念;
  • core 核心代码,包含一些工具(util.js)、事件(event.js)、唯一ID(guid.js)、矩阵运算有关(matrix.js)等;
  • dom HandleProxy.js dom事件有关;
  • graphic 图形有关,shape文件夹下就是各个图形的js文件;
  • mixin 混入模式要混入的函数;
  • tool 工具函数,包括颜色工具(color.js),path工具(path.js)和转换工具(transformPath.js);
  • vml IE中的画笔,[vml解释](http://www.g168.net/txt/vml/])

全局的文件:

  • config.js 配置文件
  • Element.js 元素文件作为zrender最基本的元素
  • Handle.js C层,控制层
  • Layer.js 图层管理
  • Painter.js V层,视图层
  • Storage.js M层,数据管理层
  • zrender.js 入口

zrender整体架构

zrender采用了MVC封装,M为Model数据层,V为View视图层,C为Controller控制层:

  • Storage(M):Storage为zrender中的Model层,它主要进行图形数据的增删改查(CRUD)操作;
  • Painter(V):Painter为zrender中的View层,它主要对canvas元素的生命周期进行管理,渲染视图以及控制更新等。定义了addHover、setBackgroundColor等方法;
  • Handler(C):Handler为zrender中的Controller层,它主要实现事件交互处理,实现完整dom事件的模拟封装。

图形

处于graphic文件夹下,zrender定义了一系列图形,供外界调用,包括圆形、矩形、心形、扇形、多边形、折线等,echarts通过调用zrender定义好的图形,可以很便捷地完成图表渲染。

Displayable

Displayable.js​为​Path、Text​等的基类,继承自​Element​,定义了setStyle、useStyle等方法,

Text

文本,继承自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文件。

Style

图形的样式文件,定义了基本的样式属性,以及样式set、clone以及判断等方法。

Path

path为图形的基类,继承自Displayable,定义了buildPath、getBoundingRect、setShape等方法,其包含this._style属性即为​Style​对象实例。

Shape

shape文件下存放着zrender定义的图形文件,扩展自Path。

Circle

圆形,通过调用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);
}

Arc

弧形,通过调用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);
}

Heart

心形❤️,通过调用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坐标)

三次被塞尔曲线绘制:

  • P0为开始点,P1为控制点1,P2为控制点2,P3为结束点
  • 取​P0P1​中点M
  • 取​P1P2​中点M’
  • 取​MM’​中点P
  • 则​P​为曲线的必经点

具体绘制图如下:

Echarts源码阅读指南_javascript

同理,我们可以绘制出左半边心形:

Echarts源码阅读指南_vue_02

Droplet

水滴形状????,通过调用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();
}

Ellipse

椭圆,通过调用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();
}

Sector

扇形,通过调用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进行开发的。


举报

相关推荐

0 条评论