2021SC@SDUSC
Legend
egend为echarts的图例组件,简单的:
legend: { data:['支出','收入'] },
展示效果图如:
legend分为两种:plain(平面)和scroll(可滚动),接下来我将分别讲解两种类型的legend是如何作用的。
Plain
legend.plain为平面的legend图例组件,主要包括LegendAction、LegendModel、LegendView文件。
LegendAction
legendAction文件中注册了legend对外API: legendToggleSelect、legendSelect以及legendUnSelect,主要代码如下:
echarts.registerAction( 'legendToggleSelect', 'legendselectchanged', zrUtil.curry(legendSelectActionHandler, 'toggleSelected') ); echarts.registerAction( 'legendSelect', 'legendselected', zrUtil.curry(legendSelectActionHandler, 'select') ); echarts.registerAction( 'legendUnSelect', 'legendunselected', zrUtil.curry(legendSelectActionHandler, 'unSelect') );
LegendFilter
legendFilter文件中实现了数据过滤,也就是当legend的isSelected方法返回为false时,则与legend name相同的series的数据则不显示,主要代码如下:
export default function (ecModel) { var legendModels = ecModel.findComponents({ mainType: 'legend' }); if (legendModels && legendModels.length) { ecModel.filterSeries(function (series) { // If in any legend component the status is not selected. // Because in legend series is assumed selected when it is not in the legend data. for (var i = 0; i < legendModels.length; i++) { if (!legendModels[i].isSelected(series.name)) { return false; } } return true; }); } }
LegendModel
legendModel通过extendComponentModel方法扩展自Component Model,重写了defaultOption属性,重写了init方法,定义了select、unSelect、toggleSelected以及isSelected等方法。
LegendView
legendView通过extendComponentView方法扩展自Component View,重写了init以及render方法对legend进行渲染,主要渲染的代码如下:
render: function (legendModel, ecModel, api) { ... // renderInner中调用了createItem方法创建Legend item // 并绑定了click、mouseover、mouseout等事件 this.renderInner(itemAlign, legendModel, ecModel, api); ... }; _createItem: function ( name, dataIndex, itemModel, legendModel, legendSymbolType, symbolType, itemAlign, color, selectMode ) { ... // 使用util/symbol导出的createSymbol方法,创建相应Type的Symbol图形 itemGroup.add(createSymbol( legendSymbolType, 0, 0, itemWidth, itemHeight, isSelected ? color : inactiveColor, // symbolKeepAspect default true for legend symbolKeepAspect == null ? true : symbolKeepAspect )); ... // 渲染legend文本 itemGroup.add(new graphic.Text({ style: graphic.setTextStyle({}, textStyleModel, { text: content, x: textX, y: itemHeight / 2, textFill: isSelected ? textStyleModel.getTextColor() : inactiveColor, textAlign: textAlign, textVerticalAlign: 'middle' }) })); // Add a invisible rect to increase the area of mouse hover // 添加legend的tooltip效果 var hitRect = new graphic.Rect({ shape: itemGroup.getBoundingRect(), invisible: true, tooltip: tooltipModel.get('show') ? zrUtil.extend({ content: name, // Defaul formatter formatter: legendGlobalTooltipModel.get('formatter', true) || function () { return name; }, formatterParams: { componentType: 'legend', legendIndex: legendModel.componentIndex, name: name, $vars: ['name'] } }, tooltipModel.option) : null }); itemGroup.add(hitRect); ... this.getContentGroup().add(itemGroup); ... return itemGroup; }
Scroll
legend.scroll为可滚动的legend图例组件,主要包括ScrollableLegendAction、ScrollableLegendModel、ScrollableLegendView文件。
ScrollableLegendAction
ScrollableLegendAction文件中注册了legend对外API:legendScroll,主要代码如下
echarts.registerAction( 'legendScroll', 'legendscroll', function (payload, ecModel) { var scrollDataIndex = payload.scrollDataIndex; scrollDataIndex != null && ecModel.eachComponent( {mainType: 'legend', subType: 'scroll', query: payload}, function (legendModel) { legendModel.setScrollDataIndex(scrollDataIndex); } ); } );
ScrollableLegendModel
ScrollableLegendModel通过extend方法扩展自LegendMode,重写了defaultOption属性,重写了init方法,定义了setScrollDataIndex以及getOrient等方法。
ScrollableLegendView
ScrollableLegendView通过extend方法扩展自LegendView,重写了init以及renderInner方法对scrollable legend进行渲染,主要渲染的代码如下:
renderInner: function (itemAlign, legendModel, ecModel, api) { var me = this; // Render content items. // 调用LegenView中renderInner渲染基本的legend视图 ScrollableLegendView.superCall(this, 'renderInner', itemAlign, legendModel, ecModel, api); // 创建分页器 var controllerGroup = this._controllerGroup; // FIXME: support be 'auto' adapt to size number text length, // e.g., '3/12345' should not overlap with the control arrow button. var pageIconSize = legendModel.get('pageIconSize', true); if (!zrUtil.isArray(pageIconSize)) { pageIconSize = [pageIconSize, pageIconSize]; } createPageButton('pagePrev', 0); var pageTextStyleModel = legendModel.getModel('pageTextStyle'); controllerGroup.add(new graphic.Text({ name: 'pageText', style: { textFill: pageTextStyleModel.getTextColor(), font: pageTextStyleModel.getFont(), textVerticalAlign: 'middle', textAlign: 'center' }, silent: true })); createPageButton('pageNext', 1); // 创建prev&next button function createPageButton(name, iconIdx) { var pageDataIndexName = name + 'DataIndex'; var icon = graphic.createIcon( legendModel.get('pageIcons', true)[legendModel.getOrient().name][iconIdx], { // Buttons will be created in each render, so we do not need // to worry about avoiding using legendModel kept in scope. onclick: zrUtil.bind( me._pageGo, me, pageDataIndexName, legendModel, api ) }, { x: -pageIconSize[0] / 2, y: -pageIconSize[1] / 2, width: pageIconSize[0], height: pageIconSize[1] } ); icon.name = name; controllerGroup.add(icon); } }