render()

in src/chart/line/LineView.ts [648:927]


    render(seriesModel: LineSeriesModel, ecModel: GlobalModel, api: ExtensionAPI) {
        const coordSys = seriesModel.coordinateSystem;
        const group = this.group;
        const data = seriesModel.getData();
        const lineStyleModel = seriesModel.getModel('lineStyle');
        const areaStyleModel = seriesModel.getModel('areaStyle');

        let points = data.getLayout('points') as number[] || [];

        const isCoordSysPolar = coordSys.type === 'polar';
        const prevCoordSys = this._coordSys;

        const symbolDraw = this._symbolDraw;
        let polyline = this._polyline;
        let polygon = this._polygon;

        const lineGroup = this._lineGroup;

        const hasAnimation = !ecModel.ssr && seriesModel.get('animation');

        const isAreaChart = !areaStyleModel.isEmpty();

        const valueOrigin = areaStyleModel.get('origin');
        const dataCoordInfo = prepareDataCoordInfo(coordSys, data, valueOrigin);

        let stackedOnPoints = isAreaChart && getStackedOnPoints(coordSys, data, dataCoordInfo);

        const showSymbol = seriesModel.get('showSymbol');

        const connectNulls = seriesModel.get('connectNulls');

        const isIgnoreFunc = showSymbol && !isCoordSysPolar
            && getIsIgnoreFunc(seriesModel, data, coordSys as Cartesian2D);

        // Remove temporary symbols
        const oldData = this._data;
        oldData && oldData.eachItemGraphicEl(function (el: SymbolExtended, idx) {
            if (el.__temp) {
                group.remove(el);
                oldData.setItemGraphicEl(idx, null);
            }
        });

        // Remove previous created symbols if showSymbol changed to false
        if (!showSymbol) {
            symbolDraw.remove();
        }

        group.add(lineGroup);

        // FIXME step not support polar
        const step = !isCoordSysPolar ? seriesModel.get('step') : false;
        let clipShapeForSymbol: PolarArea | Cartesian2DArea;
        if (coordSys && coordSys.getArea && seriesModel.get('clip', true)) {
            clipShapeForSymbol = coordSys.getArea();
            // Avoid float number rounding error for symbol on the edge of axis extent.
            // See #7913 and `test/dataZoom-clip.html`.
            if ((clipShapeForSymbol as Cartesian2DArea).width != null) {
                (clipShapeForSymbol as Cartesian2DArea).x -= 0.1;
                (clipShapeForSymbol as Cartesian2DArea).y -= 0.1;
                (clipShapeForSymbol as Cartesian2DArea).width += 0.2;
                (clipShapeForSymbol as Cartesian2DArea).height += 0.2;
            }
            else if ((clipShapeForSymbol as PolarArea).r0) {
                (clipShapeForSymbol as PolarArea).r0 -= 0.5;
                (clipShapeForSymbol as PolarArea).r += 0.5;
            }
        }
        this._clipShapeForSymbol = clipShapeForSymbol;
        const visualColor = getVisualGradient(data, coordSys, api)
            || data.getVisual('style')[data.getVisual('drawType')];
        // Initialization animation or coordinate system changed
        if (
            !(polyline && prevCoordSys.type === coordSys.type && step === this._step)
        ) {
            showSymbol && symbolDraw.updateData(data, {
                isIgnore: isIgnoreFunc,
                clipShape: clipShapeForSymbol,
                disableAnimation: true,
                getSymbolPoint(idx) {
                    return [points[idx * 2], points[idx * 2 + 1]];
                }
            });

            hasAnimation && this._initSymbolLabelAnimation(
                data,
                coordSys,
                clipShapeForSymbol
            );

            if (step) {
                if (stackedOnPoints) {
                    stackedOnPoints = turnPointsIntoStep(stackedOnPoints, points, coordSys, step, connectNulls);
                }
                // TODO If stacked series is not step
                points = turnPointsIntoStep(points, null, coordSys, step, connectNulls);
            }

            polyline = this._newPolyline(points);
            if (isAreaChart) {
                polygon = this._newPolygon(
                    points, stackedOnPoints
                );
            }// If areaStyle is removed
            else if (polygon) {
                lineGroup.remove(polygon);
                polygon = this._polygon = null;
            }

            // NOTE: Must update _endLabel before setClipPath.
            if (!isCoordSysPolar) {
                this._initOrUpdateEndLabel(seriesModel, coordSys as Cartesian2D, convertToColorString(visualColor));
            }

            lineGroup.setClipPath(
                createLineClipPath(this, coordSys, true, seriesModel)
            );
        }
        else {
            if (isAreaChart && !polygon) {
                // If areaStyle is added
                polygon = this._newPolygon(
                    points, stackedOnPoints
                );
            }
            else if (polygon && !isAreaChart) {
                // If areaStyle is removed
                lineGroup.remove(polygon);
                polygon = this._polygon = null;
            }

            // NOTE: Must update _endLabel before setClipPath.
            if (!isCoordSysPolar) {
                this._initOrUpdateEndLabel(seriesModel, coordSys as Cartesian2D, convertToColorString(visualColor));
            }

            // Update clipPath
            const oldClipPath = lineGroup.getClipPath();
            if (oldClipPath) {
                const newClipPath = createLineClipPath(this, coordSys, false, seriesModel);
                graphic.initProps(oldClipPath, {
                    shape: newClipPath.shape
                }, seriesModel);
            }
            else {
                lineGroup.setClipPath(
                    createLineClipPath(this, coordSys, true, seriesModel)
                );
            }

            // Always update, or it is wrong in the case turning on legend
            // because points are not changed.
            showSymbol && symbolDraw.updateData(data, {
                isIgnore: isIgnoreFunc,
                clipShape: clipShapeForSymbol,
                disableAnimation: true,
                getSymbolPoint(idx) {
                    return [points[idx * 2], points[idx * 2 + 1]];
                }
            });

            // In the case data zoom triggered refreshing frequently
            // Data may not change if line has a category axis. So it should animate nothing.
            if (!isPointsSame(this._stackedOnPoints, stackedOnPoints)
                || !isPointsSame(this._points, points)
            ) {
                if (hasAnimation) {
                    this._doUpdateAnimation(
                        data, stackedOnPoints, coordSys, api, step, valueOrigin, connectNulls
                    );
                }
                else {
                    // Not do it in update with animation
                    if (step) {
                        if (stackedOnPoints) {
                            stackedOnPoints = turnPointsIntoStep(stackedOnPoints, points, coordSys, step, connectNulls);
                        }
                        // TODO If stacked series is not step
                        points = turnPointsIntoStep(points, null, coordSys, step, connectNulls);
                    }

                    polyline.setShape({
                        points: points
                    });
                    polygon && polygon.setShape({
                        points: points,
                        stackedOnPoints: stackedOnPoints
                    });
                }
            }
        }

        const emphasisModel = seriesModel.getModel('emphasis');
        const focus = emphasisModel.get('focus');
        const blurScope = emphasisModel.get('blurScope');
        const emphasisDisabled = emphasisModel.get('disabled');

        polyline.useStyle(zrUtil.defaults(
            // Use color in lineStyle first
            lineStyleModel.getLineStyle(),
            {
                fill: 'none',
                stroke: visualColor,
                lineJoin: 'bevel' as CanvasLineJoin
            }
        ));

        setStatesStylesFromModel(polyline, seriesModel, 'lineStyle');

        if (polyline.style.lineWidth > 0 && seriesModel.get(['emphasis', 'lineStyle', 'width']) === 'bolder') {
            const emphasisLineStyle = polyline.getState('emphasis').style;
            emphasisLineStyle.lineWidth = +polyline.style.lineWidth + 1;
        }

        // Needs seriesIndex for focus
        getECData(polyline).seriesIndex = seriesModel.seriesIndex;
        toggleHoverEmphasis(polyline, focus, blurScope, emphasisDisabled);

        const smooth = getSmooth(seriesModel.get('smooth'));
        const smoothMonotone = seriesModel.get('smoothMonotone');

        polyline.setShape({
            smooth,
            smoothMonotone,
            connectNulls
        });

        if (polygon) {
            const stackedOnSeries = data.getCalculationInfo('stackedOnSeries');
            let stackedOnSmooth = 0;

            polygon.useStyle(zrUtil.defaults(
                areaStyleModel.getAreaStyle(),
                {
                    fill: visualColor,
                    opacity: 0.7,
                    lineJoin: 'bevel' as CanvasLineJoin,
                    decal: data.getVisual('style').decal
                }
            ));

            if (stackedOnSeries) {
                stackedOnSmooth = getSmooth(stackedOnSeries.get('smooth'));
            }

            polygon.setShape({
                smooth,
                stackedOnSmooth,
                smoothMonotone,
                connectNulls
            });

            setStatesStylesFromModel(polygon, seriesModel, 'areaStyle');
            // Needs seriesIndex for focus
            getECData(polygon).seriesIndex = seriesModel.seriesIndex;
            toggleHoverEmphasis(polygon, focus, blurScope, emphasisDisabled);
        }

        const changePolyState = this._changePolyState;

        data.eachItemGraphicEl(function (el) {
            // Switch polyline / polygon state if element changed its state.
            el && ((el as ECElement).onHoverStateChange = changePolyState);
        });

        (this._polyline as ECElement).onHoverStateChange = changePolyState;

        this._data = data;
        // Save the coordinate system for transition animation when data changed
        this._coordSys = coordSys;
        this._stackedOnPoints = stackedOnPoints;
        this._points = points;
        this._step = step;
        this._valueOrigin = valueOrigin;

        if (seriesModel.get('triggerLineEvent')) {
            this.packEventData(seriesModel, polyline);
            polygon && this.packEventData(seriesModel, polygon);
        }
    }