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