This is an automated email from the ASF dual-hosted git repository. ovilia pushed a commit to branch feat-bar-race in repository https://gitbox.apache.org/repos/asf/incubator-echarts.git
commit 03fee21840cffae72e214fd2188523857fd85ade Author: Ovilia <zwl.s...@gmail.com> AuthorDate: Wed Jul 29 19:08:14 2020 +0800 fix(bar-race): fix label animation #12484 --- src/action/changeAxisOrder.ts | 5 + src/chart/bar/BarView.ts | 322 +++++++++++++---------- src/component/axis/AxisBuilder.ts | 5 +- src/coord/Axis.ts | 10 +- src/coord/cartesian/defaultAxisExtentFromData.ts | 8 +- src/scale/Ordinal.ts | 33 ++- src/scale/Scale.ts | 7 + src/util/graphic.ts | 53 ++-- 8 files changed, 277 insertions(+), 166 deletions(-) diff --git a/src/action/changeAxisOrder.ts b/src/action/changeAxisOrder.ts index c270dae..dd74b7e 100644 --- a/src/action/changeAxisOrder.ts +++ b/src/action/changeAxisOrder.ts @@ -41,6 +41,11 @@ echarts.registerAction({ ecModel.eachComponent( { mainType: componentType, query: payload }, function (componentModel) { + // console.log('in action') + if (payload.sortInfo) { + // console.log(payload.sortInfo); + componentModel.axis.setCategorySortInfo(payload.sortInfo); + } } ); }); diff --git a/src/chart/bar/BarView.ts b/src/chart/bar/BarView.ts index a1d4d0d..90855b1 100644 --- a/src/chart/bar/BarView.ts +++ b/src/chart/bar/BarView.ts @@ -17,6 +17,10 @@ * under the License. */ +import Path, {PathProps} from 'zrender/src/graphic/Path'; +import Group from 'zrender/src/graphic/Group'; +import {extend, map, defaults, each} from 'zrender/src/core/util'; +import type {RectLike} from 'zrender/src/core/BoundingRect'; import { Rect, Sector, @@ -29,8 +33,6 @@ import { import { getECData } from "../../util/ecData"; import { enableHoverEmphasis, setStatesStylesFromModel } from '../../util/states'; import { setLabelStyle, getLabelStatesModels } from '../../label/labelStyle'; -import Path, { PathProps } from 'zrender/src/graphic/Path'; -import Group from 'zrender/src/graphic/Group'; import {throttle} from '../../util/throttle'; import {createClipPath} from '../helper/createClipPathFromCoordSys'; import Sausage from '../../util/shape/sausage'; @@ -45,20 +47,23 @@ import { OrdinalSortInfo, Payload, OrdinalNumber, - ParsedValue + ParsedValue, + ECElement } from '../../util/types'; -import BarSeriesModel, { BarSeriesOption, BarDataItemOption } from './BarSeries'; +import BarSeriesModel, {BarSeriesOption, BarDataItemOption} from './BarSeries'; import type Axis2D from '../../coord/cartesian/Axis2D'; import type Cartesian2D from '../../coord/cartesian/Cartesian2D'; -import type { RectLike } from 'zrender/src/core/BoundingRect'; import type Model from '../../model/Model'; import { isCoordinateSystemType } from '../../coord/CoordinateSystem'; import { getDefaultLabel } from '../helper/labelHelper'; import OrdinalScale from '../../scale/Ordinal'; import AngleAxis from '../../coord/polar/AngleAxis'; import RadiusAxis from '../../coord/polar/RadiusAxis'; -import { extend, map, defaults, each } from 'zrender/src/core/util'; import SeriesModel from '../../model/Series'; +import {AngleAxisModel, RadiusAxisModel} from '../../coord/polar/AxisModel'; +import CartesianAxisModel from '../../coord/cartesian/AxisModel'; +import {LayoutRect} from '../../util/layout'; +import Animator from 'zrender/src/animation/Animator'; const BAR_BORDER_WIDTH_QUERY = ['itemStyle', 'borderWidth'] as const; const BAR_BORDER_RADIUS_QUERY = ['itemStyle', 'borderRadius'] as const; @@ -108,12 +113,19 @@ class BarView extends ChartView { private _isLargeDraw: boolean; + private _isFirstFrame: boolean; // First frame after series added + private _backgroundGroup: Group; private _backgroundEls: (Rect | Sector)[]; private _model: BarSeriesModel; + constructor () { + super(); + this._isFirstFrame = true; + } + render(seriesModel: BarSeriesModel, ecModel: GlobalModel, api: ExtensionAPI, payload: Payload) { this._model = seriesModel; @@ -132,6 +144,8 @@ class BarView extends ChartView { else if (__DEV__) { console.warn('Only cartesian2d and polar supported for bar.'); } + + this._isFirstFrame = false; } incrementalPrepareRender(seriesModel: BarSeriesModel): void { @@ -168,25 +182,27 @@ class BarView extends ChartView { const coord = seriesModel.coordinateSystem; const baseAxis = coord.getBaseAxis(); - let valueAxis: Axis2D | RadiusAxis | AngleAxis; let isHorizontalOrRadial: boolean; + let lastAnimator: Animator<any> = null; + if (coord.type === 'cartesian2d') { isHorizontalOrRadial = (baseAxis as Axis2D).isHorizontal(); - valueAxis = coord.getOtherAxis(baseAxis as Axis2D); } else if (coord.type === 'polar') { isHorizontalOrRadial = baseAxis.dim === 'angle'; - valueAxis = coord.getOtherAxis(baseAxis as (AngleAxis | RadiusAxis)); } const animationModel = seriesModel.isAnimationEnabled() ? seriesModel : null; - const axisAnimationModel = baseAxis.model; const axis2DModel = (baseAxis as Axis2D).model; const axisSort = coord.type === 'cartesian2d' && axis2DModel.get('sort') && axis2DModel.get('sortSeriesIndex') === seriesModel.seriesIndex; const realtimeSort = axisSort && axis2DModel.get('realtimeSort'); + if (realtimeSort && this._isFirstFrame) { + this._initSort(data, isHorizontalOrRadial, baseAxis as Axis2D, api); + return; + } const needsClip = seriesModel.get('clip', true); const coordSysClipArea = getClipArea(coord, data); @@ -195,8 +211,6 @@ class BarView extends ChartView { // We don't use clipPath in normal mode because we needs a perfect animation // And don't want the label are clipped. - const labelModel = seriesModel.getModel('label'); - const roundCap = seriesModel.get('roundCap', true); const drawBackground = seriesModel.get('showBackground', true); @@ -206,49 +220,19 @@ class BarView extends ChartView { const bgEls: BarView['_backgroundEls'] = []; const oldBgEls = this._backgroundEls; - let hasDuringForOneData = false; - let getDuring: () => (() => void) = () => { - return null; - }; - if (coord.type === 'cartesian2d') { - const oldOrder = (baseAxis.scale as OrdinalScale).getCategorySortInfo(); + const realtimeDuring = () => { const orderMap = (idx: number) => { - return data.get(valueAxis.dim, idx) as number; - }; - - if (realtimeSort) { - // Sort in animation during - const isOrderChanged = this._isDataOrderChanged(data, orderMap, oldOrder); - if (isOrderChanged) { - getDuring = () => { - if (!hasDuringForOneData) { - hasDuringForOneData = true; - return () => { - const orderMap = (idx: number) => { - const el = (data.getItemGraphicEl(idx) as Rect); - if (el) { - const shape = el.shape; - return isHorizontalOrRadial ? shape.y + shape.height : shape.x + shape.width; - } - else { - return 0; - } - }; - that._updateSort(data, orderMap, baseAxis as Axis2D, api); - }; - } - else { - return () => null; - } - }; + const el = (data.getItemGraphicEl(idx) as Rect); + if (el) { + const shape = el.shape; + return isHorizontalOrRadial ? shape.y + shape.height : shape.x + shape.width; } - } - else if (axisSort) { - // Sort now in the first frame - this._updateSort(data, orderMap, baseAxis as Axis2D, api); - } - } - + else { + return 0; + } + }; + that._updateSort(data, orderMap, baseAxis as Axis2D, api); + }; data.diff(oldData) .add(function (dataIndex) { @@ -288,17 +272,38 @@ class BarView extends ChartView { layout, isHorizontalOrRadial, animationModel, + baseAxis.model, false, - getDuring(), roundCap ); - data.setItemGraphicEl(dataIndex, el); - group.add(el); updateStyle( el, data, dataIndex, itemModel, layout, seriesModel, isHorizontalOrRadial, coord.type === 'polar' ); + + if (realtimeSort) { + (el as ECElement).disableLabelAnimation = true; + + const animator = updateRealtimeAnimation( + seriesModel, + axis2DModel, + animationModel, + el as Rect, + layout as LayoutRect, + data, + dataIndex, + isHorizontalOrRadial, + false + ); + animator && (lastAnimator = animator); + } + else if (coord.type === 'cartesian2d') { + initProps(el, {shape: layout} as any, seriesModel, dataIndex); + } + + data.setItemGraphicEl(dataIndex, el); + group.add(el); }) .update(function (newIndex, oldIndex) { const itemModel = data.getItemModel(newIndex); @@ -316,13 +321,14 @@ class BarView extends ChartView { const bgLayout = getLayout[coord.type](data, newIndex); const shape = createBackgroundShape(isHorizontalOrRadial, bgLayout, coord); updateProps( - bgEl as Path, { shape: shape }, animationModel, newIndex + bgEl as Path, {shape: shape as RectShape}, animationModel, newIndex ); } let el = oldData.getItemGraphicEl(oldIndex) as BarPossiblePath; if (!data.hasValue(newIndex)) { group.remove(el); + el = null; return; } @@ -334,58 +340,7 @@ class BarView extends ChartView { } } - if (el) { - if (coord.type === 'cartesian2d' - && baseAxis.type === 'category' && (baseAxis as Axis2D).model.get('sort') - ) { - const rect = layout as RectShape; - let seriesShape; - let axisShape; - if (baseAxis.dim === 'x') { - axisShape = { - x: rect.x, - width: rect.width - }; - seriesShape = { - y: rect.y, - height: rect.height - }; - } - else { - axisShape = { - y: rect.y, - height: rect.height - }; - seriesShape = { - x: rect.x, - width: rect.width - }; - } - - if (!isReorder) { - updateProps( - el as Path, - { shape: seriesShape }, - animationModel, - newIndex, - null, - getDuring() - ); - } - updateProps(el as Path, { shape: axisShape }, axisAnimationModel, newIndex, null); - } - else { - updateProps(el as Path, { - shape: layout - }, animationModel, newIndex, null); - } - - const defaultTextGetter = (values: ParsedValue | ParsedValue[]) => { - return getDefaultLabel(seriesModel.getData(), newIndex, values); - }; - updateLabel(el, data, newIndex, labelModel, seriesModel, animationModel, defaultTextGetter); - } - else { + if (!el) { el = elementCreator[coord.type]( seriesModel, data, @@ -393,20 +348,40 @@ class BarView extends ChartView { layout, isHorizontalOrRadial, animationModel, - true, - getDuring(), + baseAxis.model, + !!el, roundCap ); } - data.setItemGraphicEl(newIndex, el); - // Add back - group.add(el); - updateStyle( el, data, newIndex, itemModel, layout, seriesModel, isHorizontalOrRadial, coord.type === 'polar' ); + + if (realtimeSort) { + (el as ECElement).disableLabelAnimation = true; + + const animator = updateRealtimeAnimation( + seriesModel, + axis2DModel, + animationModel, + el as Rect, + layout as LayoutRect, + data, + newIndex, + isHorizontalOrRadial, + false + ); + animator && (lastAnimator = animator); + } + else if (coord.type === 'cartesian2d') { + updateProps(el, {shape: layout}, seriesModel, newIndex, null); + } + + data.setItemGraphicEl(newIndex, el); + // Add back + group.add(el); }) .remove(function (dataIndex) { const el = oldData.getItemGraphicEl(dataIndex) as Path; @@ -424,6 +399,10 @@ class BarView extends ChartView { this._backgroundEls = bgEls; this._data = data; + + if (lastAnimator) { + lastAnimator.during(realtimeDuring); + } } private _renderLarge(seriesModel: BarSeriesModel, ecModel: GlobalModel, api: ExtensionAPI): void { @@ -515,19 +494,34 @@ class BarView extends ChartView { const oldOrder = (baseAxis.scale as OrdinalScale).getCategorySortInfo(); const isOrderChanged = this._isDataOrderChanged(data, orderMap, oldOrder); if (isOrderChanged) { - // re-sort and update in axis - const sortInfo = this._dataSort(data, orderMap); - baseAxis.setCategorySortInfo(sortInfo); - const action = { type: 'changeAxisOrder', componentType: baseAxis.dim + 'Axis', - axisId: baseAxis.index + axisId: baseAxis.index, + sortInfo: this._dataSort(data, orderMap) } as Payload; api.dispatchAction(action); } } + _initSort( + data: List<BarSeriesModel, DefaultDataVisual>, + isHorizontal: boolean, + baseAxis: Axis2D, + api: ExtensionAPI + ) { + const action = { + type: 'changeAxisOrder', + componentType: baseAxis.dim + 'Axis', + axisId: baseAxis.index, + sortInfo: this._dataSort( + data, + idx => parseInt(data.get(isHorizontal ? 'y' : 'x', idx) as string, 10) + ) + } as Payload; + api.dispatchAction(action); + } + remove() { this._clear(this._model); } @@ -547,6 +541,7 @@ class BarView extends ChartView { group.removeAll(); } this._data = null; + this._isFirstFrame = true; } private _removeBackground(): void { @@ -608,7 +603,9 @@ interface ElementCreator { ( seriesModel: BarSeriesModel, data: List, newIndex: number, layout: RectLayout | SectorLayout, isHorizontalOrRadial: boolean, - animationModel: BarSeriesModel, isUpdate: boolean, during: () => void, + animationModel: BarSeriesModel, + axisModel: CartesianAxisModel | AngleAxisModel | RadiusAxisModel, + isUpdate: boolean, roundCap?: boolean ): BarPossiblePath } @@ -619,7 +616,7 @@ const elementCreator: { cartesian2d( seriesModel, data, newIndex, layout: RectLayout, isHorizontal, - animationModel, isUpdate, during + animationModel, axisModel, isUpdate, roundCap ) { const rect = new Rect({ shape: extend({}, layout), @@ -628,34 +625,17 @@ const elementCreator: { rect.name = 'item'; - // Animation if (animationModel) { const rectShape = rect.shape; const animateProperty = isHorizontal ? 'height' : 'width' as 'width' | 'height'; - const animateTarget = {} as RectShape; rectShape[animateProperty] = 0; - animateTarget[animateProperty] = layout[animateProperty]; - - (isUpdate ? updateProps : initProps)(rect, { - shape: animateTarget - }, animationModel, newIndex, null, during); - - const defaultTextGetter = (values: ParsedValue | ParsedValue[]) => { - return getDefaultLabel(seriesModel.getData(), newIndex, values); - }; - - const labelModel = seriesModel.getModel('label'); - (isUpdate ? updateLabel : initLabel)( - rect, data, newIndex, labelModel, seriesModel, animationModel, defaultTextGetter - ); } - return rect; }, polar( seriesModel, data, newIndex, layout: SectorLayout, isRadial: boolean, - animationModel, isUpdate, during, roundCap + animationModel, axisModel, isUpdate, roundCap ) { // Keep the same logic with bar in catesion: use end value to control // direction. Notice that if clockwise is true (by default), the sector @@ -689,6 +669,68 @@ const elementCreator: { } }; +function updateRealtimeAnimation( + seriesModel: BarSeriesModel, + axisModel: CartesianAxisModel, + animationModel: BarSeriesModel, + el: Rect, + layout: LayoutRect, + data: List, + newIndex: number, + isHorizontal: boolean, + isUpdate: boolean +) { + // Animation + if (animationModel || axisModel) { + let seriesTarget; + let axisTarget; + if (isHorizontal) { + axisTarget = { + x: layout.x, + width: layout.width + }; + seriesTarget = { + y: layout.y, + height: layout.height + }; + } + else { + axisTarget = { + y: layout.y, + height: layout.height + }; + seriesTarget = { + x: layout.x, + width: layout.width + }; + } + + (isUpdate ? updateProps : initProps)(el, { + shape: seriesTarget + }, seriesModel, newIndex, null); + + const lastAnimator = el.animators.length + ? el.animators[el.animators.length - 1] + : null; + + (isUpdate ? updateProps : initProps)(el, { + shape: axisTarget + }, axisModel, newIndex); + + const defaultTextGetter = (values: ParsedValue | ParsedValue[]) => { + return getDefaultLabel(seriesModel.getData(), newIndex, values); + }; + + const labelModel = seriesModel.getModel('label'); + (isUpdate ? updateLabel : initLabel)( + el, data, newIndex, labelModel, seriesModel, animationModel, defaultTextGetter + ); + + // TODO: + return lastAnimator; + } +} + interface GetLayout { (data: List, dataIndex: number, itemModel?: Model<BarDataItemOption>): RectLayout | SectorLayout } diff --git a/src/component/axis/AxisBuilder.ts b/src/component/axis/AxisBuilder.ts index 3430c31..733c3fb 100644 --- a/src/component/axis/AxisBuilder.ts +++ b/src/component/axis/AxisBuilder.ts @@ -32,6 +32,7 @@ import { ZRTextVerticalAlign, ZRTextAlign, ECElement, ColorString } from '../../ import { AxisBaseOption } from '../../coord/axisCommonTypes'; import Element from 'zrender/src/Element'; import { PathStyleProps } from 'zrender/src/graphic/Path'; +import OrdinalScale from '../../scale/Ordinal'; const PI = Math.PI; @@ -751,7 +752,9 @@ function buildAxisLabel( const triggerEvent = axisModel.get('triggerEvent'); each(labels, function (labelItem, index) { - const tickValue = labelItem.tickValue; + const tickValue = axis.scale.type === 'ordinal' + ? (axis.scale as OrdinalScale).getRawIndex(labelItem.tickValue) + : labelItem.tickValue; const formattedLabel = labelItem.formattedLabel; const rawLabel = labelItem.rawLabel; diff --git a/src/coord/Axis.ts b/src/coord/Axis.ts index 0cfb43e..f314526 100644 --- a/src/coord/Axis.ts +++ b/src/coord/Axis.ts @@ -177,10 +177,12 @@ class Axis { const ticksCoords = map(ticks, function (tickVal) { return { - coord: this.dataToCoord(tickVal), - tickValue: this.scale instanceof OrdinalScale - ? this.scale.getCategoryIndex(tickVal) - : tickVal + coord: this.dataToCoord( + this.scale.type === 'ordinal' + ? (this.scale as OrdinalScale).getRawIndex(tickVal) + : tickVal + ), + tickValue: tickVal }; }, this); diff --git a/src/coord/cartesian/defaultAxisExtentFromData.ts b/src/coord/cartesian/defaultAxisExtentFromData.ts index 2b0e58e..b82391b 100644 --- a/src/coord/cartesian/defaultAxisExtentFromData.ts +++ b/src/coord/cartesian/defaultAxisExtentFromData.ts @@ -136,7 +136,7 @@ function calculateFilteredExtent( // For duplication removal. const condDimMap: Dictionary<boolean> = {}; const tarDimMap: Dictionary<boolean> = {}; - let condAxisExtent: number[]; + let condAxis: Axis; let tarAxisRecord: AxisRecord; function addCondition(axis: Axis, axisRecord: AxisRecord) { @@ -150,7 +150,7 @@ function calculateFilteredExtent( each(getDataDimensionsOnAxis(data, axis.dim), function (dataDim) { if (!hasOwn(condDimMap, dataDim)) { condDimMap[dataDim] = true; - condAxisExtent = [rawExtentResult.min, rawExtentResult.max]; + condAxis = axis; } }); } @@ -196,7 +196,7 @@ function calculateFilteredExtent( if (singleCondDim && singleTarDim) { for (let dataIdx = 0; dataIdx < dataLen; dataIdx++) { const condVal = data.get(singleCondDim, dataIdx) as number; - if (condVal >= condAxisExtent[0] && condVal <= condAxisExtent[1]) { + if (condAxis.scale.isInExtentRange(condVal)) { unionExtent(tarDimExtents[0], data.get(singleTarDim, dataIdx) as number); } } @@ -205,7 +205,7 @@ function calculateFilteredExtent( for (let dataIdx = 0; dataIdx < dataLen; dataIdx++) { for (let j = 0; j < condDimsLen; j++) { const condVal = data.get(condDims[j], dataIdx) as number; - if (condVal >= condAxisExtent[0] && condVal <= condAxisExtent[1]) { + if (condAxis.scale.isInExtentRange(condVal)) { for (let k = 0; k < tarDimsLen; k++) { unionExtent(tarDimExtents[k], data.get(tarDims[k], dataIdx) as number); } diff --git a/src/scale/Ordinal.ts b/src/scale/Ordinal.ts index a0374f4..0a566d0 100644 --- a/src/scale/Ordinal.ts +++ b/src/scale/Ordinal.ts @@ -92,7 +92,7 @@ class OrdinalScale extends Scale { while (rank <= extent[1]) { ticks.push({ - value: rank + value: this.getCategoryIndex(rank) }); rank++; } @@ -113,6 +113,11 @@ class OrdinalScale extends Scale { return this._categorySortInfo; } + /** + * Get display order after sort + * + * @param {OrdinalNumber} n index of raw data + */ getCategoryIndex(n: OrdinalNumber): OrdinalNumber { if (this._categorySortInfo.length) { return this._categorySortInfo[n].beforeSortIndex; @@ -123,11 +128,26 @@ class OrdinalScale extends Scale { } /** + * Get raw data index + * + * @param {OrdinalNumber} displayIndex index of display + */ + getRawIndex(displayIndex: OrdinalNumber): OrdinalNumber { + if (this._categorySortInfo.length) { + return this._categorySortInfo[displayIndex].ordinalNumber; + } + else { + return displayIndex; + } + } + + /** * Get item on rank n */ getLabel(tick: ScaleTick): string { if (!this.isBlank()) { - const cateogry = this._ordinalMeta.categories[tick.value]; + const rawIndex = this.getRawIndex(tick.value); + const cateogry = this._ordinalMeta.categories[rawIndex]; // Note that if no data, ordinalMeta.categories is an empty array. // Return empty if it's not exist. return cateogry == null ? '' : cateogry + ''; @@ -142,6 +162,15 @@ class OrdinalScale extends Scale { this.unionExtent(data.getApproximateExtent(dim)); } + /** + * @override + * If value is in extent range + */ + isInExtentRange(value: number): boolean { + value = this.getCategoryIndex(value); + return this._extent[0] <= value && this._extent[1] >= value; + } + getOrdinalMeta(): OrdinalMeta { return this._ordinalMeta; } diff --git a/src/scale/Scale.ts b/src/scale/Scale.ts index 0bfd5fc..2b90b6c 100644 --- a/src/scale/Scale.ts +++ b/src/scale/Scale.ts @@ -110,6 +110,13 @@ abstract class Scale { } /** + * If value is in extent range + */ + isInExtentRange(value: number): boolean { + return this._extent[0] <= value && this._extent[1] >= value; + } + + /** * When axis extent depends on data and no data exists, * axis ticks should not be drawn, which is named 'blank'. */ diff --git a/src/util/graphic.ts b/src/util/graphic.ts index b351969..bf93f6a 100644 --- a/src/util/graphic.ts +++ b/src/util/graphic.ts @@ -70,6 +70,7 @@ import List from '../data/List'; import { getLabelText } from '../label/labelStyle'; import { AnimationEasing } from 'zrender/src/animation/easing'; import { getECData } from './ecData'; +import {makeInner} from './model'; const mathMax = Math.max; @@ -80,6 +81,10 @@ const _customShapeMap: Dictionary<{ new(): Path }> = {}; type ExtendShapeOpt = Parameters<typeof Path.extend>[0]; type ExtendShapeReturn = ReturnType<typeof Path.extend>; +const innerLabel = makeInner<{ + startValue: number | (string | number)[], + nextValue: number | (string | number)[] +}, ZRText>(); /** * Extend shape with parameters @@ -544,7 +549,9 @@ function animateOrSetLabel<Props extends PathProps>( const valueAnimationEnabled = labelModel && labelModel.get('valueAnimation'); if (valueAnimationEnabled) { const precisionOption = labelModel.get('precision'); - const precision: number = precisionOption === 'auto' ? 0 : precisionOption; + const precision: number = !precisionOption || precisionOption === 'auto' + ? 0 + : precisionOption; let interpolateValues: (number | string)[] | (number | string); const rawValues = seriesModel.getRawValue(dataIndex); @@ -563,10 +570,23 @@ function animateOrSetLabel<Props extends PathProps>( } } + const text = el.getTextContent(); + const host = text && innerLabel(text); + host && (host.startValue = host.nextValue); + const during = (percent: number) => { + const text = el.getTextContent(); + if (!text || !host) { + return; + } + let interpolated; if (isRawValueNumber) { - const value = interpolateNumber(0, interpolateValues as number, percent); + const value = interpolateNumber( + host.startValue as number || 0, + interpolateValues as number, + percent + ); interpolated = numberUtil.round(value, precision); } else { @@ -578,23 +598,26 @@ function animateOrSetLabel<Props extends PathProps>( interpolated[i] = (rawValues as [])[i]; } else { - const value = interpolateNumber(0, (interpolateValues as number[])[i], percent); + const value = interpolateNumber( + (host.startValue as number[])[i] || 0, + (interpolateValues as number[])[i], + percent + ); interpolated[i] = numberUtil.round(value), precision; } } } - const text = el.getTextContent(); - if (text) { - const labelText = getLabelText({ - labelDataIndex: dataIndex, - labelFetcher: seriesModel, - defaultText: defaultTextGetter - ? defaultTextGetter(interpolated) - : interpolated + '' - }, {normal: labelModel}, interpolated); - text.style.text = labelText.normal; - text.dirty(); - } + host.nextValue = interpolated; + + const labelText = getLabelText({ + labelDataIndex: dataIndex, + labelFetcher: seriesModel, + defaultText: defaultTextGetter + ? defaultTextGetter(interpolated) + : interpolated + '' + }, {normal: labelModel}, interpolated); + text.style.text = labelText.normal; + text.dirty(); }; const props: ElementProps = {}; --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@echarts.apache.org For additional commands, e-mail: commits-h...@echarts.apache.org