分析完echarts简单的结构之后,我们就进入到了Component源码解读,在这篇博文中,我将主要介绍各Component的渲染过程以及其使用的zrender graphic。希望和小伙伴们一起进步呀!!加油!!
前言
echarts对Component的定义呢,可以认为是除Series外的其他配置项,在这篇博文中我们将探讨title(图标标题)、legend(图例组件)、AxisPointer(坐标轴指示器)、坐标系以及坐标轴这些Component。
用户通过传递option对象来设置相应的Component。
在这部分中echarts采用了Model以及View的架构来管理Component:
- Model:model/Component.js 管理Component数据
- View:view/Component.js 负责渲染Component视图
Model层
model/Component.js。Component扩展自Model(Model是Echarts中最基本的元素,其定义了mergeOption等方法,混合了LineStyle、AraeStyle、ItemStyle以及TextStyle),重写了init及mergeOption等方法,定义了mergeDefaultAndTheme、getDefaultOption等方法以及defaultOption(Component默认配置)、componentIndex等属性。
View层
view/Component.js。Component中定义了group等属性以及init、render、dispose等方法。
快速扩展
在echarts中定义了extendComponentModel以及extendComponentView方法,可以让Component对Model以及View进行快速扩展
1 | export function extendComponentModel(opts) { |
Title
title是我们在使用echarts图表时设置的标题组件,简单的🌰:
1 | title: { |
title文件中Model部分通过extendComponentModel方法扩展自Component Model,重写了defaultOption属性,用于设置title的默认option。
View部分通过extendComponentView方法扩展Component View,重写了render方法对title进行渲染,主要代码如下:
1 | render: function (titleModel, ecModel, api) { |
title文本渲染主要是通过zrender graphic中的Text进行渲染的,通过zrender Style中定义的setStyle方法对元素进行样式设定。
Legend
legend为echarts的图例组件,简单的🌰:
1 | legend: { |
展示效果图如:
legend分为两种:plain(平面)和scroll(可滚动),接下来我将分别讲解两种类型的legend是如何作用的。
Plain
legend.plain为平面的legend图例组件,主要包括LegendAction、LegendModel、LegendView文件。
LegendAction
legendAction文件中注册了legend对外API: legendToggleSelect、legendSelect以及legendUnSelect,主要代码如下:
1 | echarts.registerAction( |
LegendFilter
legendFilter文件中实现了数据过滤,也就是当legend的isSelected方法返回为false时,则与legend name相同的series的数据则不显示,主要代码如下:
1 | export default function (ecModel) { |
LegendModel
legendModel通过extendComponentModel方法扩展自Component Model,重写了defaultOption属性,重写了init方法,定义了select、unSelect、toggleSelected以及isSelected等方法。
LegendView
legendView通过extendComponentView方法扩展自Component View,重写了init以及render方法对legend进行渲染,主要渲染的代码如下:
1 | render: function (legendModel, ecModel, api) { |
Scroll
legend.scroll为可滚动的legend图例组件,主要包括ScrollableLegendAction、ScrollableLegendModel、ScrollableLegendView文件。
ScrollableLegendAction
ScrollableLegendAction文件中注册了legend对外API:legendScroll,主要代码如下:
1 | echarts.registerAction( |
ScrollableLegendModel
ScrollableLegendModel通过extend方法扩展自LegendMode,重写了defaultOption属性,重写了init方法,定义了setScrollDataIndex以及getOrient等方法。
ScrollableLegendView
ScrollableLegendView通过extend方法扩展自LegendView,重写了init以及renderInner方法对scrollable legend进行渲染,主要渲染的代码如下:
1 | renderInner: function (itemAlign, legendModel, ecModel, api) { |
AxisPointer
AxisPointer为echarts中的坐标指示器,包括直角坐标以及极坐标等。
AxisPointer.js
axisPointer.js文件中注册了axisPointer对外api,主要代码如下:
1 | echarts.registerAction({ |
存储coordSysAxesInfo信息,主要代码如下:
1 | echarts.registerProcessor(echarts.PRIORITY.PROCESSOR.STATISTIC, function (ecModel, api) { |
AxisPointerModel
AxisPointerModel通过extendComponentModel方法扩展自Component Model,重写了defaultOption属性。
AxisPointerView
AxisPointerView过extendComponentModel方法扩展自Component View,重写了render、remove以及dispose方法。
BaseAxisPointer
BaseAxisPointer为CartesianAxisPointer、PolarAxisPointer等的基类,重写了render以及renderHandler等方法。renderHandler主要是定义move、drag等情况时视图更新方法。
render主要代码:
1 | render: function (axisModel, axisPointerModel, api, forceRender) { |
CartesianAxisPointer
CartesianAxisPointer使用extend方法扩展自BaseAxisPointer,重写了makeElOption、getHandleTransform以及updateHandleTransform方法。makeElOption主要代码如下:
1 | makeElOption: function (elOption, value, axisModel, axisPointerModel, api) { |
SingleAxisPointer
SingleAxisPointer同CartesianAxisPointer。
PolarAxisPointer
PolarAxisPointer使用extend扩展自BaseAxisPointer,重写了makeElOption方法,主要代码如下:
1 | makeElOption: function (elOption, value, axisModel, axisPointerModel, api) { |
坐标轴
公共文件
在直角坐标系以及极坐标系等坐标轴组件中,存在着多个公共文件。
AxisView
AxisView通过extendComponentView方法扩展自Component Model,重写了render、remove以及dispose方法,定义了updateAxisPointer方法。
AxisBuilder
AxisBuilder中定义了axisLine、axisTickLabel以及axisName的渲染方法,主要代码如下:
1 | var builders = { |
AxisModelCreator
AxisModelCreator为生成AxisModel的方法,其在AxisModel的基础上扩展了getCategories、getOrdinalMeta、mergeDefaultAndTheme等方法,重写了defaultOption属性,并通过:
1 | ComponentModel.registerSubTypeDefaulter( |
来注册相应的Axis子类,如xAxis、yAxis、radiusAxis以及angleAxis等。
直角坐标轴 Axis
Axis为直角坐标系Grid中的坐标轴,包括xAxis(x轴)以及yAxis(y轴)。
AxisModel
AxisModel通过extend方法扩展自Component Model,重写了init、mergeOption、,并使用AxisModelCreator分别创建额xAxisModel以及yAxisModel,
CartesianAxisView
CartesianAxisView通过extend方法扩展自AxisView,重写了render方法,定义了splitLine以及splitArea方法,并扩展了xAxis以及yAxis View。主要代码如下:
1 | var CartesianAxisView = AxisView.extend({ |
极坐标轴 AngleAxis&RadiusAxis
每一个极坐标都拥有一个角度轴AngleAxis和一个半径轴RadiusAxis。
公共文件
AxisModel
AxisModel通过extend方法扩展自Component Model,定义了getCoordSysModel方法,并根据不同option创建了angle和radius Model,主要代码如下:
1 | axisModelCreator('angle', PolarAxisModel, getAxisType, polarAxisDefaultExtendedOption.angle); |
角度轴 AngleAxis
AngleAxis为极坐标Polar中的角度轴,
AngleAxisView
AngleAxisView通过extend方法扩展自AxisView,重写了render方法,并定义了axisLine、axisTick、axisLabel、splitLine以及splitArea等方法,主要代码如下:
1 | render: function (angleAxisModel, ecModel) { |
半径轴 RadiusAxis
RadiusAxis为极坐标Polar中的半径轴。
RadiusAxisView
RadiusAxisView通过extend方法扩展自AxisView,重写了render方法,并定义了splitLine、splitArea方法,主要代码如下:
1 | _splitLine: function (radiusAxisModel, polar, axisAngle, radiusExtent, ticksCoords) { |
雷达坐标轴
RadarView
RadarView通过extendComponentView方法扩展自Component View,重写了render方法,主要代码如下:
1 | render: function (radarModel, ecModel, api) { |
RadarModel
RadarModel通过extendComponentModel扩展自Component Model,重写了defaultOption属性以及optionUpdated方法。
平行坐标轴 ParallelAxis
ParallelModel
ParallelModel使用extend方法扩展自Component Model,重写了defaultOption属性,并重写了init、mergeOption等方法。
ParallelAxisAction
parallelAxisAction中注册了axisAreaSelected以及parallelAxisExpand API,主要代码如下:
1 | var actionInfo = { |
ParallelAxisView
ParallelAxisView使用extendComponentView方法扩展自Component View,重写了render等方法。渲染代码如下:
1 | render: function (axisModel, ecModel, api, payload) { |
单轴 SingleAxis
SingleCreator
SingleCreator文件主要为创建单轴的逻辑代码,主要代码如下:
1 | function create(ecModel, api) { |
AxisModel
axisModel扩展自Component Model,重写了defaultOption属性
SingleAxisView
SingleAxisView使用extend方法扩展自AxisView,重写了render方法,并定义了splitLine方法,实现代码如下:
1 | render: function (axisModel, ecModel, api, payload) { |
坐标系
在上一节中,我们介绍了直角坐标轴、极坐标轴以及雷达坐标轴,我们将在这节解读坐标轴是如何在坐标系中展示的。
公共文件
Axis
Axis对象中定义了scale、dim等属性以及contain、containData、getExtent、getTicksCoords、getViewLabels等方法。
Grid 直角坐标系
Grid为echarts中的直角坐标系组件。
gridSimple
gridSimple通过extendComponentView扩展自Component View,重写了render方法,主要代码如下:
1 | render: function (gridModel, ecModel) { |
Grid
coord/cartesian/Grid.js,实现直角坐标系的渲染,主要代码如下:
1 | function Grid(gridModel, ecModel, api) { |
Polar 极坐标系
Polar为echarts中的极坐标系组件,每一个极坐标都拥有一个角度轴和一个半径轴。
Polar
Polar定义了angleAxis(new RadiusAxis())、radiusAxis(new AngleAxis())等属性以及containPoint、containData、getAxis、getAngleAxis、getRadiusAxis等方法。
PolarCreator
PolarCreator用于创建极坐标系,主要代码如下:
1 | create: function (ecModel, api) { |
Radar 雷达坐标系
Radar为echarts中的雷达坐标系组件。
###Radar
Radar文件位于coord/radar目录下,定义了getIndicatorAxes、coordToPoint、dataToPoint等方法,并注册了雷达坐标信息,主要代码为:
1 | function Radar(radarModel, ecModel, api) { |
Parallel 平行坐标系
Parallel为echarts中的平行坐标系组件。
Parallel
Parallel定义了rect、dimensions等属性以及init、containPoint、getRect、getAxis、axisCoordToPoint等方法。
ParallelCreator
ParallelCreator用于创建平行坐标系,主要代码如下:
1 | function create(ecModel, api) { |
geo 地理坐标系
geo.js
geo.js中注册了geoToggleSelect、geoSelect、geoUnSelect等action
GeoMode
GeoModel通过extend方法扩展自Component Model,重写了defaultOption属性以及init、optionUpdated方法,并定义了getRegionModel、getFormattedLabel、setZoom以及setCenter方法。
geoCreator
geoCreator用于创建Geo 地理坐标系
GeoView
GeoView通过extendComponentView扩展自Compnent View,重写了init、render以及dispose方法,主要代码如下:
1 | init: function (ecModel, api) { |
MapDraw
MapDraw, 主要绘制代码如下:
1 | draw: function (mapOrGeoModel, ecModel, api, fromView, payload) { |
geoRoam
geoRoam中注册了geoRoam api,trigger中调用了geoModel的setCenter及setZoom方法来更新视图。
Calendar 日历坐标系
calendar.js
calendar.js创建日历坐标系
CalendarModel
CalendarModel通过extend方法扩展自Component Model,重写了defaultOption属性以及init、mergeOption方法。
CalendarView
CalendarView通过extendComponentView扩展自Component View,重写了render方法,主要代码如下:
1 | render: function (calendarModel, ecModel, api) { |
问题
在解读的过程中,我们需要带着问题去思考源码的实现,在这里我们来解决echarts是如何渲染展示坐标轴上的label数据这个问题。
存储
首先考虑label data的存储过程,以直角坐标系为🌰,data存储的调用链如下所示:
- echarts.setOption()
- Global.setOption()
- Global.mergeOption()
- Component.optionUpdated() (Model)
- AxisModelCreator.optionUpdated(),将OrdinalMeta.createByAxisModel()返回的数据保存在this.__ordinalMeta中
- OrdinalMeta.createByAxisModel(),主要代码如下:
1 | OrdinalMeta.createByAxisModel = function (axisModel) { |
- Grid.js中通过:
1 | var axis = new Axis2D( |
创建坐标轴,createScaleByModel方法获取保存在this.__ordinalMeta属性中的数据,并返回OrdinalScale对象,createScaleByModel方法主要代码如下所示:
1 | export function createScaleByModel(model, axisType) { |
Grid创建坐标轴时将返回的OrdinalScale对象数据作为scale属性保存在axis中,主要代码如下:
1 | var Axis2D = function (dim, scale, coordExtent, axisType, position) { |
获取
获取
- AxisBuilder axisTickLabel()
- AxisBuilder buildAxisLabel()
- labels = axis.getViewLabels() => coord/Axis.js getViewLabels()
- 调用createAxisLabels(),返回result.labels
- axisTickLabelBuilder createAxisLabels()
1 | export function createAxisLabels(axis) { |
- axisTickLabelBuilder makeCategoryLabels()
1 | function makeCategoryLabels(axis) { |
- axisTickLabelBuilder makeCategoryLabelsActually()
- axisTickLabelBuilder makeLabelsByCustomizedCategoryInterval()
1 | function makeLabelsByCustomizedCategoryInterval(axis, categoryInterval, onlyTick) { |
渲染
AxisBuilder通过axis.getViewLabels()获取labels数据后通过graphic.Text进行渲染,通过graphic.setStyle设置文本样式,主要代码如下:
1 | each(labels, function (labelItem, index) { |
总结
这篇博文很大,简单介绍了title、legend、axisPointer、坐标系以及坐标轴等组件的渲染细节,也探讨了坐标轴上label 数据的存储、获取以及渲染的过程。
希望能够跟小伙伴们一起进步呀!继续加油!!