From 358915d30de95c4399542905585385ec8c0dd803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogus=C5=82aw=20Skrzypkowiak?= <228489+b091@users.noreply.github.com> Date: Mon, 12 Oct 2026 15:35:55 +0400 Subject: [PATCH] fix(universalTransition): skip array seriesKey members missing from the old series When a series declares an array seriesKey and its members change between updates (e.g. a pie whose categories shrink after filtering), findTransitionSeriesBatches looked up each member in oldDataMap and dereferenced undefined. The throw also skipped saving the old series, so every later update threw again. --- src/animation/universalTransition.ts | 2 +- test/ut/spec/series/pie.test.ts | 58 ++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 test/ut/spec/series/pie.test.ts diff --git a/src/animation/universalTransition.ts b/src/animation/universalTransition.ts index a87668d336..c3b28875f1 100644 --- a/src/animation/universalTransition.ts +++ b/src/animation/universalTransition.ts @@ -623,7 +623,7 @@ function findTransitionSeriesBatches( const oldSeries: TransitionSeries[] = []; each(transitionKey, key => { const oldData = oldDataMap.get(key); - if (oldData.data) { + if (oldData && oldData.data) { oldSeries.push({ dataGroupId: oldData.dataGroupId, divide: getDivideShapeFromData(oldData.data), diff --git a/test/ut/spec/series/pie.test.ts b/test/ut/spec/series/pie.test.ts new file mode 100644 index 0000000000..b5aafcab77 --- /dev/null +++ b/test/ut/spec/series/pie.test.ts @@ -0,0 +1,58 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +import { createChart, removeChart } from '../../core/utHelper'; +import { EChartsType } from '@/src/echarts'; + +describe('pie universalTransition', function () { + + let chart: EChartsType; + beforeEach(function () { + chart = createChart({ width: 400, height: 300 }); + }); + + afterEach(function () { + removeChart(chart); + }); + + function pieWithSeriesKey(groups: string[]) { + return { + series: [{ + type: 'pie', + universalTransition: { + enabled: true, + seriesKey: groups.map(group => 'metric-' + group) + }, + data: groups.map((group, idx) => ({ name: group, value: idx + 1 })) + }] + }; + } + + // An array seriesKey whose members no longer match the previous update (e.g. a pie whose + // categories shrink after filtering) must skip the transition instead of throwing. + it('should not throw when an array seriesKey has members missing from the old series', function () { + chart.setOption(pieWithSeriesKey(['A', 'B'])); + + expect(() => chart.setOption(pieWithSeriesKey(['B']), { replaceMerge: ['series'] })).not.toThrow(); + // The old series snapshot must be refreshed too, or every later update throws again. + expect(() => chart.setOption(pieWithSeriesKey(['B']), { replaceMerge: ['series'] })).not.toThrow(); + expect((chart as any).getModel().getSeriesByIndex(0).getData().count()).toBe(1); + }); + +});