From 154f3ce56be5b2b9d48772bf0a42838586402cca Mon Sep 17 00:00:00 2001 From: tiwarir Date: Wed, 22 Jul 2026 15:38:13 -0400 Subject: [PATCH] fix(core): preserve event query context. close #21584 --- src/core/echarts.ts | 12 ++++- src/util/ECEventProcessor.ts | 4 -- test/ut/spec/api/event.test.ts | 99 ++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 test/ut/spec/api/event.test.ts diff --git a/src/core/echarts.ts b/src/core/echarts.ts index 8214c11e0e..9f5b1ab88c 100644 --- a/src/core/echarts.ts +++ b/src/core/echarts.ts @@ -1357,14 +1357,22 @@ class ECharts extends Eventful { params.event = e; params.type = eveName; - (this._$eventProcessor as ECEventProcessor).eventInfo = { + const eventProcessor = this._$eventProcessor as ECEventProcessor; + // A user handler may synchronously trigger another ECharts event. + const previousEventInfo = eventProcessor.eventInfo; + eventProcessor.eventInfo = { targetEl: el, packedEvent: params, model: model, view: view }; - this.trigger(eveName, params); + try { + this.trigger(eveName, params); + } + finally { + eventProcessor.eventInfo = previousEventInfo; + } } }; // Consider that some component (like tooltip, brush, ...) diff --git a/src/util/ECEventProcessor.ts b/src/util/ECEventProcessor.ts index a0d8e91a20..578471df70 100644 --- a/src/util/ECEventProcessor.ts +++ b/src/util/ECEventProcessor.ts @@ -144,8 +144,4 @@ export class ECEventProcessor implements EventProcessor { } } - afterTrigger() { - // Make sure the eventInfo won't be used in next trigger. - this.eventInfo = null; - } }; diff --git a/test/ut/spec/api/event.test.ts b/test/ut/spec/api/event.test.ts new file mode 100644 index 0000000000..81aeb4d752 --- /dev/null +++ b/test/ut/spec/api/event.test.ts @@ -0,0 +1,99 @@ +/* +* 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 { EChartsType } from '../../../../src/echarts'; +import { createChart, getECModel } from '../../core/utHelper'; + +describe('api/event', function () { + + let chart: EChartsType; + + beforeEach(function () { + chart = createChart(); + }); + + afterEach(function () { + chart.dispose(); + }); + + it('should preserve the event query context when a handler calls setOption', function () { + chart.setOption({ + xAxis: { + type: 'category', + data: ['Mon', 'Tue'] + }, + yAxis: { + type: 'value' + }, + series: [ + { + id: 'first', + type: 'line', + data: [1, 2] + }, + { + id: 'second', + type: 'line', + data: [2, 3] + } + ] + }); + + const triggeredSeries: string[] = []; + + chart.on('click', {seriesId: 'first'}, function () { + triggeredSeries.push('first'); + chart.setOption({ + series: [{ + id: 'first', + data: [3, 4] + }] + }); + }); + chart.on('click', {seriesId: 'second'}, function () { + triggeredSeries.push('second'); + }); + + const target = getECModel(chart) + .getSeriesByIndex(0) + .getData() + .getItemGraphicEl(0); + + chart.getZr().trigger('click', { + target: target, + offsetX: 10, + offsetY: 10 + }); + + expect(triggeredSeries).toEqual(['first']); + + const secondTarget = getECModel(chart) + .getSeriesByIndex(1) + .getData() + .getItemGraphicEl(0); + + chart.getZr().trigger('click', { + target: secondTarget, + offsetX: 10, + offsetY: 10 + }); + + expect(triggeredSeries).toEqual(['first', 'second']); + }); +});