Echarts项目源代码分析

2021SC@SDUSC

Legend

egend为echarts的图例组件,简单的:

legend: {
    data:['支出','收入']
},

展示效果图如:

Echarts项目源代码分析

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);
    }
}

 

上一篇:vue+echarts封装组件


下一篇:vue使用echarts