From 8575bb150ab8a99f4e2b29a6e4762dc80082e206 Mon Sep 17 00:00:00 2001 From: hujie <1239912649@qq.com> Date: Fri, 15 Aug 2025 13:51:21 +0800 Subject: [PATCH 1/5] fix: theme-switch-keep-data. close apache##21200 --- src/core/echarts.ts | 12 +++-- test/theme-switch-keep-data.html | 92 ++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 test/theme-switch-keep-data.html diff --git a/src/core/echarts.ts b/src/core/echarts.ts index fe5b995ece..35ec6c8ffb 100644 --- a/src/core/echarts.ts +++ b/src/core/echarts.ts @@ -744,6 +744,8 @@ class ECharts extends Eventful { return; } + const backup = this.getOption ? this.getOption() : null; + let silent = opts && opts.silent; let updateParams = null as UpdateLifecycleParams; @@ -761,9 +763,6 @@ class ECharts extends Eventful { try { this._updateTheme(theme); ecModel.setTheme(this._theme); - - prepare(this); - updateMethods.update.call(this, {type: 'setTheme'}, updateParams); } catch (e) { this[IN_MAIN_PROCESS_KEY] = false; @@ -772,6 +771,13 @@ class ECharts extends Eventful { this[IN_MAIN_PROCESS_KEY] = false; + if (backup) { + this.setOption(backup as any, { notMerge: true, lazyUpdate: false, silent: !!silent }); + return; + } + + prepare(this); + updateMethods.update.call(this, {type: 'setTheme'}, updateParams); flushPendingActions.call(this, silent); triggerUpdatedEvent.call(this, silent); } diff --git a/test/theme-switch-keep-data.html b/test/theme-switch-keep-data.html new file mode 100644 index 0000000000..635f6c0a74 --- /dev/null +++ b/test/theme-switch-keep-data.html @@ -0,0 +1,92 @@ + + + + + + + Apache ECharts Basic Example + + + + + + +
+ + + + + + + + + + From 6c4ba79cf8ce09cca0a8be764991ca46e1e71e4c Mon Sep 17 00:00:00 2001 From: hujie <1239912649@qq.com> Date: Mon, 18 Aug 2025 11:09:43 +0800 Subject: [PATCH 2/5] fix: getOption does not exist --- src/core/echarts.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/echarts.ts b/src/core/echarts.ts index 35ec6c8ffb..5afcd97e26 100644 --- a/src/core/echarts.ts +++ b/src/core/echarts.ts @@ -744,7 +744,7 @@ class ECharts extends Eventful { return; } - const backup = this.getOption ? this.getOption() : null; + const backup = typeof this.getOption === 'function' ? this.getOption() : null; let silent = opts && opts.silent; let updateParams = null as UpdateLifecycleParams; From 25650790a4fe10424454b73475dcf96a0dcc0ad6 Mon Sep 17 00:00:00 2001 From: hujie <1239912649@qq.com> Date: Wed, 27 Aug 2025 17:30:08 +0800 Subject: [PATCH 3/5] fix: Change the thought process --- src/model/Global.ts | 21 +++++--- test/theme-switch-keep-data.html | 92 ++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 7 deletions(-) create mode 100644 test/theme-switch-keep-data.html diff --git a/src/model/Global.ts b/src/model/Global.ts index c1e2be3250..8cfd9575a9 100644 --- a/src/model/Global.ts +++ b/src/model/Global.ts @@ -242,14 +242,14 @@ class GlobalModel extends Model { * @return Whether option changed. */ resetOption( - type: 'recreate' | 'timeline' | 'media', + type: 'recreate' | 'timeline' | 'media'| 'theme', opt?: Pick ): boolean { return this._resetOption(type, normalizeSetOptionInput(opt)); } private _resetOption( - type: 'recreate' | 'timeline' | 'media', + type: 'recreate' | 'timeline' | 'media'| 'theme', opt: InnerSetOptionOpts ): boolean { let optionChanged = false; @@ -283,6 +283,13 @@ class GlobalModel extends Model { // If we really need to modify a props in each `MediaUnit['option']`, use the full version // (`{baseOption, media}`) in `setOption`. // For `timeline`, the case is the same. + if (type === 'theme') { + const themeOption = this._theme.option; + if (themeOption) { + optionChanged = true; + this._mergeOption({ theme: themeOption }, opt); + } + } if (!type || type === 'recreate' || type === 'timeline') { const timelineOption = optionManager.getTimelineOption(this); @@ -322,6 +329,9 @@ class GlobalModel extends Model { resetSourceDefaulter(this); + if (newOption.theme) { + mergeTheme(option, newOption.theme); + } // If no component class, merge directly. // For example: color, animaiton options, etc. each(newOption, function (componentOption, mainType: ComponentMainType) { @@ -547,7 +557,7 @@ echarts.use([${seriesImportName}]);`); setTheme(theme: object) { this._theme = new Model(theme); - this._resetOption('recreate', null); + this._resetOption('theme', null); } getTheme(): Model { @@ -1012,8 +1022,7 @@ function isNotTargetSeries(seriesModel: SeriesModel, payload: Payload): boolean } function mergeTheme(option: ECUnitOption, theme: ThemeOption): void { - // PENDING - // NOT use `colorLayer` in theme if option has `color` + const notMergeColorLayer = option.color && !option.colorLayer; each(theme, function (themeItem, name) { @@ -1023,8 +1032,6 @@ function mergeTheme(option: ECUnitOption, theme: ThemeOption): void { return; } - // If it is component model mainType, the model handles that merge later. - // otherwise, merge them here. if (!ComponentModel.hasClass(name)) { if (typeof themeItem === 'object') { option[name] = !option[name] diff --git a/test/theme-switch-keep-data.html b/test/theme-switch-keep-data.html new file mode 100644 index 0000000000..635f6c0a74 --- /dev/null +++ b/test/theme-switch-keep-data.html @@ -0,0 +1,92 @@ + + + + + + + Apache ECharts Basic Example + + + + + + +
+ + + + + + + + + + From f72bb3f963571e673fc75f685b867c1be6e593a9 Mon Sep 17 00:00:00 2001 From: hujie <1239912649@qq.com> Date: Wed, 27 Aug 2025 17:42:59 +0800 Subject: [PATCH 4/5] fix: Restore the original code --- src/core/echarts.ts | 12 +++--------- src/model/Global.ts | 5 ++++- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/core/echarts.ts b/src/core/echarts.ts index 5afcd97e26..fe5b995ece 100644 --- a/src/core/echarts.ts +++ b/src/core/echarts.ts @@ -744,8 +744,6 @@ class ECharts extends Eventful { return; } - const backup = typeof this.getOption === 'function' ? this.getOption() : null; - let silent = opts && opts.silent; let updateParams = null as UpdateLifecycleParams; @@ -763,6 +761,9 @@ class ECharts extends Eventful { try { this._updateTheme(theme); ecModel.setTheme(this._theme); + + prepare(this); + updateMethods.update.call(this, {type: 'setTheme'}, updateParams); } catch (e) { this[IN_MAIN_PROCESS_KEY] = false; @@ -771,13 +772,6 @@ class ECharts extends Eventful { this[IN_MAIN_PROCESS_KEY] = false; - if (backup) { - this.setOption(backup as any, { notMerge: true, lazyUpdate: false, silent: !!silent }); - return; - } - - prepare(this); - updateMethods.update.call(this, {type: 'setTheme'}, updateParams); flushPendingActions.call(this, silent); triggerUpdatedEvent.call(this, silent); } diff --git a/src/model/Global.ts b/src/model/Global.ts index 8cfd9575a9..29e1ca40d4 100644 --- a/src/model/Global.ts +++ b/src/model/Global.ts @@ -1022,7 +1022,8 @@ function isNotTargetSeries(seriesModel: SeriesModel, payload: Payload): boolean } function mergeTheme(option: ECUnitOption, theme: ThemeOption): void { - + // PENDING + // NOT use `colorLayer` in theme if option has `color` const notMergeColorLayer = option.color && !option.colorLayer; each(theme, function (themeItem, name) { @@ -1032,6 +1033,8 @@ function mergeTheme(option: ECUnitOption, theme: ThemeOption): void { return; } + // If it is component model mainType, the model handles that merge later. + // otherwise, merge them here. if (!ComponentModel.hasClass(name)) { if (typeof themeItem === 'object') { option[name] = !option[name] From 03e13c26383189dd20f1bf3a5ea2b8d29092b944 Mon Sep 17 00:00:00 2001 From: hujie <1239912649@qq.com> Date: Fri, 26 Sep 2025 22:42:13 +0800 Subject: [PATCH 5/5] fix: Scene issue --- src/model/Global.ts | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/model/Global.ts b/src/model/Global.ts index 29e1ca40d4..331685e63f 100644 --- a/src/model/Global.ts +++ b/src/model/Global.ts @@ -242,14 +242,14 @@ class GlobalModel extends Model { * @return Whether option changed. */ resetOption( - type: 'recreate' | 'timeline' | 'media'| 'theme', + type: 'recreate' | 'timeline' | 'media', opt?: Pick ): boolean { return this._resetOption(type, normalizeSetOptionInput(opt)); } private _resetOption( - type: 'recreate' | 'timeline' | 'media'| 'theme', + type: 'recreate' | 'timeline' | 'media' | 'theme', opt: InnerSetOptionOpts ): boolean { let optionChanged = false; @@ -286,8 +286,8 @@ class GlobalModel extends Model { if (type === 'theme') { const themeOption = this._theme.option; if (themeOption) { + mergeTheme(this.option, themeOption, true); optionChanged = true; - this._mergeOption({ theme: themeOption }, opt); } } @@ -328,10 +328,6 @@ class GlobalModel extends Model { const replaceMergeMainTypeMap = opt && opt.replaceMergeMainTypeMap; resetSourceDefaulter(this); - - if (newOption.theme) { - mergeTheme(option, newOption.theme); - } // If no component class, merge directly. // For example: color, animaiton options, etc. each(newOption, function (componentOption, mainType: ComponentMainType) { @@ -1021,7 +1017,7 @@ function isNotTargetSeries(seriesModel: SeriesModel, payload: Payload): boolean } } -function mergeTheme(option: ECUnitOption, theme: ThemeOption): void { +function mergeTheme(option: ECUnitOption, theme: ThemeOption, preserveUserOptions?: boolean): void { // PENDING // NOT use `colorLayer` in theme if option has `color` const notMergeColorLayer = option.color && !option.colorLayer; @@ -1039,7 +1035,9 @@ function mergeTheme(option: ECUnitOption, theme: ThemeOption): void { if (typeof themeItem === 'object') { option[name] = !option[name] ? clone(themeItem) - : merge(option[name], themeItem, false); + : preserveUserOptions + ? merge(themeItem, option[name], false) // User options have higher priority + : merge(option[name], themeItem, false); // Theme has higher priority } else { if (option[name] == null) {