This is an automated email from the ASF dual-hosted git repository. sushuang pushed a commit to branch PR/plainheart_fix/alignTicks-precision in repository https://gitbox.apache.org/repos/asf/echarts.git
commit b094f987ddf00b43341c1bf73055c9a8babf9132 Author: 100pah <[email protected]> AuthorDate: Tue Mar 10 17:39:48 2026 +0800 fix(toolbox): Fix that toolbox theme cause corresponding icons are always displayed even if not required. See #21176 . --- src/component/toolbox/ToolboxModel.ts | 51 ++++++++++-- src/model/Component.ts | 4 +- test/lib/testHelper.js | 2 +- test/toolbox-custom.html | 153 ++++++++++++++++++++++++++++++++++ 4 files changed, 199 insertions(+), 11 deletions(-) diff --git a/src/component/toolbox/ToolboxModel.ts b/src/component/toolbox/ToolboxModel.ts index 49debe77b..27037e3ae 100644 --- a/src/component/toolbox/ToolboxModel.ts +++ b/src/component/toolbox/ToolboxModel.ts @@ -17,7 +17,6 @@ * under the License. */ -import * as zrUtil from 'zrender/src/core/util'; import * as featureManager from './featureManager'; import ComponentModel from '../../model/Component'; import { @@ -31,9 +30,13 @@ import { CommonTooltipOption, Dictionary, ComponentOnCalendarOptionMixin, - ComponentOnMatrixOptionMixin + ComponentOnMatrixOptionMixin, + NullUndefined } from '../../util/types'; import tokens from '../../visual/tokens'; +import type GlobalModel from '../../model/Global'; +import type Model from '../../model/Model'; +import { each, extend, merge } from 'zrender/src/core/util'; export interface ToolboxTooltipFormatterParams { @@ -93,19 +96,49 @@ class ToolboxModel extends ComponentModel<ToolboxOption> { ignoreSize: true } as const; - optionUpdated() { - super.optionUpdated.apply(this, arguments as any); - const {ecModel} = this; + private _themeFeatureOption: ToolboxOption['feature']; + + init(option: ToolboxOption, parentModel: Model, ecModel: GlobalModel): void { + // An historical behavior: + // An initial ec option + // chart.setOption( {toolbox: {feature: { featureA: {}, featureB: {}, }} } ) + // indicates the declared toolbox features need to be enabled regardless of whether property + // "show" is explicity specified. But the subsequent `setOption` in merge mode requires property + // "show: false" to be explicity specified if intending to remove features, for example: + // chart.setOption( {toolbox: {feature: { featureA: {show: false}, featureC: {} } ) + // We keep backward compatibility and perform specific processing to prevent theme + // settings from breaking it. + const toolboxOptionInTheme = ecModel.getTheme().get('toolbox'); + const themeFeatureOption = toolboxOptionInTheme ? toolboxOptionInTheme.feature : null; + if (themeFeatureOption) { + // Use extend - the first level of the feature option will be modified later. + this._themeFeatureOption = extend({}, themeFeatureOption); + toolboxOptionInTheme.feature = {}; + } - zrUtil.each(this.option.feature, function (featureOpt, featureName) { + super.init(option, parentModel, ecModel); // merge theme is performed inside it. + + if (themeFeatureOption) { + toolboxOptionInTheme.feature = themeFeatureOption; // Recover + } + } + + optionUpdated() { + each(this.option.feature, function (featureOpt, featureName) { + const themeFeatureOption = this._themeFeatureOption; const Feature = featureManager.getFeature(featureName); if (Feature) { if (Feature.getDefaultOption) { - Feature.defaultOption = Feature.getDefaultOption(ecModel); + Feature.defaultOption = Feature.getDefaultOption(this.ecModel); + } + if (themeFeatureOption && themeFeatureOption[featureName]) { + merge(featureOpt, themeFeatureOption[featureName]); + // Follow the previous behavior, theme is only be merged once. + themeFeatureOption[featureName] = null; } - zrUtil.merge(featureOpt, Feature.defaultOption); + merge(featureOpt, Feature.defaultOption); } - }); + }, this); } static defaultOption: ToolboxOption = { diff --git a/src/model/Component.ts b/src/model/Component.ts index 3ff62785f..a2a938f25 100644 --- a/src/model/Component.ts +++ b/src/model/Component.ts @@ -191,7 +191,9 @@ class ComponentModel<Opt extends ComponentOption = ComponentOption> extends Mode /** * Called immediately after `init` or `mergeOption` of this instance called. */ - optionUpdated(newCptOption: Opt, isInit: boolean): void {} + optionUpdated(newCptOption: Opt, isInit: boolean): void { + // MUST NOT do anything here. + } /** * [How to declare defaultOption]: diff --git a/test/lib/testHelper.js b/test/lib/testHelper.js index fee04790d..67b95a7bc 100644 --- a/test/lib/testHelper.js +++ b/test/lib/testHelper.js @@ -1819,7 +1819,7 @@ if (theme == null && window.__ECHARTS__DEFAULT__THEME__) { theme = window.__ECHARTS__DEFAULT__THEME__; } - if (theme) { + if (typeof theme === 'string') { require(['theme/' + theme]); } diff --git a/test/toolbox-custom.html b/test/toolbox-custom.html index 5c89fad38..91eee32b1 100644 --- a/test/toolbox-custom.html +++ b/test/toolbox-custom.html @@ -30,7 +30,10 @@ under the License. <link rel="stylesheet" href="lib/reset.css" /> </head> <body> + <div id="main0"></div> + <div id="main_update"></div> + <script> require(['echarts'], function (echarts) { @@ -84,6 +87,156 @@ under the License. </script> + + + <script> + require([ + 'echarts', + ], function (echarts) { + var _ctx = { + featureList: [ + 'saveAsImage', + 'myTool1', + ], + }; + _ctx.lastFeatureList = _ctx.featureList; + + var MY_THEME = { + toolbox: { + feature: { + // dataView panel theme is customized. + dataView: { + backgroundColor: 'blue', + textColor: 'black', + textareaColor: 'green', + textareaBorderColor: 'green', + buttonColor: 'black', + buttonTextColor: 'green' + } + } + }, + }; + + var allFeatures = { + restore: {}, + saveAsImage: {}, + dataZoom: {}, + dataView: {}, + myTool1: { + title: 'myTool1', + icon: 'path://M432.45,595.444c0,2.177-4.661,6.82-11.305,6.82c-6.475,0-11.306-4.567-11.306-6.82s4.852-6.812,11.306-6.812C427.841,588.632,432.452,593.191,432.45,595.444L432.45,595.444z M421.155,589.876c-3.009,0-5.448,2.495-5.448,5.572s2.439,5.572,5.448,5.572c3.01,0,5.449-2.495,5.449-5.572C426.604,592.371,424.165,589.876,421.155,589.876L421.155,589.876z M421.146,591.891c-1.916,0-3.47,1.589-3.47,3.549c0,1.959,1.554,3.548,3.47,3.548s3.469-1.589,3.469-3.548C424.614,593.479, [...] + onclick: function (){ + alert('myToolHandler1') + } + }, + myTool2: { + show: true, + title: 'myTool2', + icon: 'image://data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7', + onclick: function () { + alert('myToolHandler2'); + } + } + }; + + function createFeaturesOption(addShowProp) { + var featureOption = {}; + var featureList = _ctx.featureList; + var lastFeatureList = _ctx.lastFeatureList; + + featureList.forEach(function (featureName) { + if (addShowProp) { + featureOption[featureName] = Object.assign({}, allFeatures[featureName]); + featureOption[featureName].show = true; + } + else { + featureOption[featureName] = allFeatures[featureName]; + } + }); + + if (addShowProp) { + lastFeatureList.forEach(function (lastFeatureName) { + if (!featureOption[lastFeatureName]) { + featureOption[lastFeatureName] = {show: false}; + } + }); + } + + return featureOption; + } + + function createOption() { + var option = { + xAxis: {}, + yAxis: {}, + series: { + type: 'line', + data: [[11, 22], [33, 44]] + }, + toolbox: { + show: true, + right: 20, + feature: createFeaturesOption() + }, + animation: false + }; + + return option; + } + + var chart = testHelper.create(echarts, 'main_update', { + title: [ + 'Init toolbox features in a theme where dataView panel is customized.', + 'In the init state, **dataView** button should not be displayed.', + ], + option: createOption(), + theme: MY_THEME, + inputsStyle: 'compact', + inputs: [{ + type: 'select', + text: 'update (merge mode, no "show" specified, expect no remove):', + values: [ + _ctx.featureList, + [], + ['restore', 'dataZoom'], + ['restore', 'saveAsImage', 'dataView', 'myTool2'] + ], + onchange() { + _ctx.lastFeatureList = _ctx.featureList; + _ctx.featureList = this.value; + chart.setOption({ + toolbox: { + feature: createFeaturesOption(false), + } + }); + } + }, { + type: 'br', + }, { + type: 'select', + text: 'update (merge mode, "show" specified, expect removable):', + values: [ + _ctx.featureList, + [], + ['restore', 'dataZoom'], + ['restore', 'saveAsImage','dataZoom','dataView','myTool1'] + ], + onchange() { + _ctx.lastFeatureList = _ctx.featureList; + _ctx.featureList = this.value; + chart.setOption({ + toolbox: { + feature: createFeaturesOption(true), + } + }); + } + }] + }); + }); + </script> + + + </body> </html> --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
