你的位置:首页 > 信息动态 > 新闻中心
信息动态
联系我们

Echarts项目源代码分析

2021/12/12 17:32:52

2021SC@SDUSC

坐标轴

公共文件 

 在直角坐标系以及极坐标系等坐标轴组件中,存在着多个公共文件。

 AxisView

 AxisView通过extendComponentView方法扩展自Component Model,重写了render、remove以及dispose方法,定义了updateAxisPointer方法。

 AxisBuilder

 AxisBuilder中定义了axisLine、axisTickLabel以及axisName的渲染方法,主要代码如下

var builders = {
    axisLine: function () {
        ...

        this.group.add(new graphic.Line(graphic.subPixelOptimizeLine({
            // Id for animation
            anid: 'line',

            shape: {
                x1: pt1[0],
                y1: pt1[1],
                x2: pt2[0],
                y2: pt2[1]
            },
            style: lineStyle,
            strokeContainThreshold: opt.strokeContainThreshold || 5,
            silent: true,
            z2: 1
        })));

        var arrows = axisModel.get('axisLine.symbol');
        var arrowSize = axisModel.get('axisLine.symbolSize');

        var arrowOffset = axisModel.get('axisLine.symbolOffset') || 0;
        if (typeof arrowOffset === 'number') {
            arrowOffset = [arrowOffset, arrowOffset];
        }

        if (arrows != null) {
            ...
            each([{
                rotate: opt.rotation + Math.PI / 2,
                offset: arrowOffset[0],
                r: 0
            }, {
                rotate: opt.rotation - Math.PI / 2,
                offset: arrowOffset[1],
                r: Math.sqrt((pt1[0] - pt2[0]) * (pt1[0] - pt2[0])
                    + (pt1[1] - pt2[1]) * (pt1[1] - pt2[1]))
            }], function (point, index) {
                // 创建arrow symbole
                if (arrows[index] !== 'none' && arrows[index] != null) {
                    var symbol = createSymbol(
                        arrows[index],
                        -symbolWidth / 2,
                        -symbolHeight / 2,
                        symbolWidth,
                        symbolHeight,
                        lineStyle.stroke,
                        true
                    );

                    // Calculate arrow position with offset
                    var r = point.r + point.offset;
                    var pos = [
                        pt1[0] + r * Math.cos(opt.rotation),
                        pt1[1] - r * Math.sin(opt.rotation)
                    ];

                    symbol.attr({
                        rotation: point.rotate,
                        position: pos,
                        silent: true,
                        z2: 11
                    });
                    this.group.add(symbol);
                }
            }, this);
        }
    },

    axisTickLabel: function () {
        var axisModel = this.axisModel;
        var opt = this.opt;
        // 通过graphic.Line以及graphic.Text分别对tick及label进行渲染
        var tickEls = buildAxisTick(this, axisModel, opt);
        var labelEls = buildAxisLabel(this, axisModel, opt);

        fixMinMaxLabelShow(axisModel, labelEls, tickEls);
    },

    axisName: function () {
        ...
        var textEl = new graphic.Text({
            // Id for animation
            anid: 'name',

            __fullText: name,
            __truncatedText: truncatedText,

            position: pos,
            rotation: labelLayout.rotation,
            silent: isSilent(axisModel),
            z2: 1,
            tooltip: (tooltipOpt && tooltipOpt.show)
                ? extend({
                    content: name,
                    formatter: function () {
                        return name;
                    },
                    formatterParams: formatterParams
                }, tooltipOpt)
                : null
        });

        graphic.setTextStyle(textEl.style, textStyleModel, {
            text: truncatedText,
            textFont: textFont,
            textFill: textStyleModel.getTextColor()
                || axisModel.get('axisLine.lineStyle.color'),
            textAlign: labelLayout.textAlign,
            textVerticalAlign: labelLayout.textVerticalAlign
        });
        ...

        // FIXME
        this._dumbGroup.add(textEl);
        textEl.updateTransform();

        this.group.add(textEl);

        textEl.decomposeTransform();
    }

};

 AxisModelCreator

 AxisModelCreator为生成AxisModel的方法,其在AxisModel的基础上扩展了getCategories、getOrdinalMeta、mergeDefaultAndTheme等方法,重写了defaultOption属性,并通过:

ComponentModel.registerSubTypeDefaulter(
    axisName + 'Axis',
    zrUtil.curry(axisTypeDefaulter, axisName)
);

 来注册相应的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。主要代码如下:

var CartesianAxisView = AxisView.extend({
    type: 'cartesianAxis',
    axisPointerClass: 'CartesianAxisPointer',
    render: function (axisModel, ecModel, api, payload) {
        ...
        // 结合AxisBuilder
        var axisBuilder = new AxisBuilder(axisModel, layout);
        zrUtil.each(axisBuilderAttrs, axisBuilder.add, axisBuilder);
        ...
        CartesianAxisView.superCall(this, 'render', axisModel, ecModel, api, payload);
    },
    ...
    _splitLine: function (axisModel, gridModel) {
        ...
        // Simple optimization
        // Batching the lines if color are the same
        for (var i = 0; i < ticksCoords.length; i++) {
            ...
            this._axisGroup.add(new graphic.Line(graphic.subPixelOptimizeLine({
                anid: tickValue != null ? 'line_' + ticksCoords[i].tickValue : null,
                shape: {
                    x1: p1[0],
                    y1: p1[1],
                    x2: p2[0],
                    y2: p2[1]
                },
                style: zrUtil.defaults({
                    stroke: lineColors[colorIndex]
                }, lineStyle),
                silent: true
            })));
        }
    },

    _splitArea: function (axisModel, gridModel) {
        ...
        for (var i = 1; i < ticksCoords.length; i++) {
            ...
            this._axisGroup.add(new graphic.Rect({
                anid: tickValue != null ? 'area_' + tickValue : null,
                shape: {
                    x: x,
                    y: y,
                    width: width,
                    height: height
                },
                style: zrUtil.defaults({
                    fill: areaColors[colorIndex]
                }, areaStyle),
                silent: true
            }));

            colorIndex = (colorIndex + 1) % areaColorsLen;
        }

        this._splitAreaColors = newSplitAreaColors;
    }
});
CartesianAxisView.extend({
    type: 'xAxis'
});
CartesianAxisView.extend({
    type: 'yAxis'
});

极坐标轴 AngleAxis&RadiusAxis

 公共文件

 AxisModel

AxisModel通过extend方法扩展自Component Model,定义了getCoordSysModel方法,并根据不同option创建了angle和radius Model,主要代码如下:

axisModelCreator('angle', PolarAxisModel, getAxisType, polarAxisDefaultExtendedOption.angle);
axisModelCreator('radius', PolarAxisModel, getAxisType, polarAxisDefaultExtendedOption.radius);

 角度轴 AngleAxis

 AngleAxis为极坐标Polar中的角度轴,

 AngleAxisView

 AngleAxisView通过extend方法扩展自AxisView,重写了render方法,并定义了axisLine、axisTick、axisLabel、splitLine以及splitArea等方法,主要代码如下:

render: function (angleAxisModel, ecModel) {
    ...
    var angleAxis = angleAxisModel.axis;
    var polar = angleAxis.polar;
    var radiusExtent = polar.getRadiusAxis().getExtent();
    var ticksAngles = angleAxis.getTicksCoords();
    var labels = zrUtil.map(angleAxis.getViewLabels(), function (labelItem) {
        var labelItem = zrUtil.clone(labelItem);
        labelItem.coord = angleAxis.dataToCoord(labelItem.tickValue);
        return labelItem;
    });
    ...
},

_axisLine: function (angleAxisModel, polar, ticksAngles, radiusExtent) {
    var lineStyleModel = angleAxisModel.getModel('axisLine.lineStyle');

    var circle = new graphic.Circle({
        shape: {
            cx: polar.cx,
            cy: polar.cy,
            r: radiusExtent[getRadiusIdx(polar)]
        },
        style: lineStyleModel.getLineStyle(),
        z2: 1,
        silent: true
    });
    circle.style.fill = null;

    this.group.add(circle);
 },
 _axisTick: function (angleAxisModel, polar, ticksAngles, radiusExtent) {
     var tickModel = angleAxisModel.getModel('axisTick');

     var tickLen = (tickModel.get('inside') ? -1 : 1) * tickModel.get('length');
     var radius = radiusExtent[getRadiusIdx(polar)];

     var lines = zrUtil.map(ticksAngles, function (tickAngleItem) {
         return new graphic.Line({
             shape: getAxisLineShape(polar, [radius, radius + tickLen], tickAngleItem.coord)
         });
     });
     this.group.add(graphic.mergePath(
         lines, {
             style: zrUtil.defaults(
                 tickModel.getModel('lineStyle').getLineStyle(),
                 {
                     stroke: angleAxisModel.get('axisLine.lineStyle.color')
                 }
             )
         }
     ));
 },
 _axisLabel: function (angleAxisModel, polar, ticksAngles, radiusExtent, labels) {
     ...
     // Use length of ticksAngles because it may remove the last tick to avoid overlapping
     zrUtil.each(labels, function (labelItem, idx) {
         ...
         var textEl = new graphic.Text({silent: true});
         this.group.add(textEl);
         graphic.setTextStyle(textEl.style, labelModel, {
             x: p[0],
             y: p[1],
             textFill: labelModel.getTextColor() || angleAxisModel.get('axisLine.lineStyle.color'),
             text: labelItem.formattedLabel,
             textAlign: labelTextAlign,
             textVerticalAlign: labelTextVerticalAlign
         });
     }, this);
 },
 _splitLine: function (angleAxisModel, polar, ticksAngles, radiusExtent) {
     ...
     for (var i = 0; i < ticksAngles.length; i++) {
         var colorIndex = (lineCount++) % lineColors.length;
         splitLines[colorIndex] = splitLines[colorIndex] || [];
         splitLines[colorIndex].push(new graphic.Line({
             shape: getAxisLineShape(polar, radiusExtent, ticksAngles[i].coord)
         }));
     }

     // Simple optimization
     // Batching the lines if color are the same
     for (var i = 0; i < splitLines.length; i++) {
         this.group.add(graphic.mergePath(splitLines[i], {
             style: zrUtil.defaults({
                 stroke: lineColors[i % lineColors.length]
             }, lineStyleModel.getLineStyle()),
             silent: true,
             z: angleAxisModel.get('z')
         }));
     }
 },
 _splitArea: function (angleAxisModel, polar, ticksAngles, radiusExtent) {
     ...
     for (var i = 1; i < ticksAngles.length; i++) {
         var colorIndex = (lineCount++) % areaColors.length;
         splitAreas[colorIndex] = splitAreas[colorIndex] || [];
         splitAreas[colorIndex].push(new graphic.Sector({
             shape: {
                 cx: polar.cx,
                 cy: polar.cy,
                 r0: r0,
                 r: r1,
                 startAngle: prevAngle,
                 endAngle: -ticksAngles[i].coord * RADIAN,
                 clockwise: clockwise
             },
             silent: true
         }));
         prevAngle = -ticksAngles[i].coord * RADIAN;
     }

     // Simple optimization
     // Batching the lines if color are the same
     for (var i = 0; i < splitAreas.length; i++) {
         this.group.add(graphic.mergePath(splitAreas[i], {
             style: zrUtil.defaults({
                 fill: areaColors[i % areaColors.length]
             }, areaStyleModel.getAreaStyle()),
             silent: true
         }));
     }
 }

 半径轴 RadiusAxis

 RadiusAxis为极坐标Polar中的半径轴。

 RadiusAxisView

 RadiusAxisView通过extend方法扩展自AxisView,重写了render方法,并定义了splitLine、splitArea方法,主要代码如下:

_splitLine: function (radiusAxisModel, polar, axisAngle, radiusExtent, ticksCoords) {
    ...
    for (var i = 0; i < ticksCoords.length; i++) {
        var colorIndex = (lineCount++) % lineColors.length;
        splitLines[colorIndex] = splitLines[colorIndex] || [];
        splitLines[colorIndex].push(new graphic.Circle({
            shape: {
                cx: polar.cx,
                cy: polar.cy,
                r: ticksCoords[i].coord
            },
            silent: true
        }));
    }

    // Simple optimization
    // Batching the lines if color are the same
    for (var i = 0; i < splitLines.length; i++) {
        this.group.add(graphic.mergePath(splitLines[i], {
            style: zrUtil.defaults({
                stroke: lineColors[i % lineColors.length],
                fill: null
            }, lineStyleModel.getLineStyle()),
            silent: true
        }));
    }
},

_splitArea: function (radiusAxisModel, polar, axisAngle, radiusExtent, ticksCoords) {
    ...
    for (var i = 1; i < ticksCoords.length; i++) {
        var colorIndex = (lineCount++) % areaColors.length;
        splitAreas[colorIndex] = splitAreas[colorIndex] || [];
        splitAreas[colorIndex].push(new graphic.Sector({
            shape: {
                cx: polar.cx,
                cy: polar.cy,
                r0: prevRadius,
                r: ticksCoords[i].coord,
                startAngle: 0,
                endAngle: Math.PI * 2
            },
            silent: true
        }));
        prevRadius = ticksCoords[i].coord;
    }

    // Simple optimization
    // Batching the lines if color are the same
    for (var i = 0; i < splitAreas.length; i++) {
        this.group.add(graphic.mergePath(splitAreas[i], {
            style: zrUtil.defaults({
                fill: areaColors[i % areaColors.length]
            }, areaStyleModel.getAreaStyle()),
            silent: true
        }));
    }
 }