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 6de824dc04448da902426e37b8988f9354884a36 Author: 100pah <[email protected]> AuthorDate: Tue Mar 10 21:39:33 2026 +0800 fix(toolbox): Simplify toolbox and fix that toolbox throw error when remove DataZoom feature. --- src/component/toolbox/ToolboxView.ts | 151 ++++++++++++++++-------------- src/component/toolbox/feature/DataView.ts | 6 +- src/component/toolbox/feature/DataZoom.ts | 7 -- src/component/toolbox/featureManager.ts | 8 +- test/toolbox-custom.html | 1 + 5 files changed, 83 insertions(+), 90 deletions(-) diff --git a/src/component/toolbox/ToolboxView.ts b/src/component/toolbox/ToolboxView.ts index d3f96d1b4..8b7c82421 100644 --- a/src/component/toolbox/ToolboxView.ts +++ b/src/component/toolbox/ToolboxView.ts @@ -17,7 +17,6 @@ * under the License. */ -import * as zrUtil from 'zrender/src/core/util'; import * as textContain from 'zrender/src/contain/text'; import * as graphic from '../../util/graphic'; import { enterEmphasis, leaveEmphasis } from '../../util/states'; @@ -28,7 +27,7 @@ import ComponentView from '../../view/Component'; import ToolboxModel from './ToolboxModel'; import GlobalModel from '../../model/Global'; import ExtensionAPI from '../../core/ExtensionAPI'; -import { DisplayState, Dictionary, Payload } from '../../util/types'; +import { DisplayState, Dictionary, Payload, NullUndefined } from '../../util/types'; import { ToolboxFeature, getFeature, @@ -42,8 +41,10 @@ import ZRText from 'zrender/src/graphic/Text'; import { getFont } from '../../label/labelStyle'; import { box, createBoxLayoutReference, getLayoutRect, positionElement } from '../../util/layout'; import tokens from '../../visual/tokens'; +import { bind, createHashMap, curry, each, filter, HashMap, isFunction, isString } from 'zrender/src/core/util'; type IconPath = ToolboxFeatureModel['iconPaths'][string]; +type FeatureName = string; type ExtendedPath = IconPath & { __title: string @@ -52,9 +53,15 @@ type ExtendedPath = IconPath & { class ToolboxView extends ComponentView { static type = 'toolbox' as const; - _features: Dictionary<ToolboxFeature | UserDefinedToolboxFeature>; + /** + * Current enabled features, including only features having `show: true`. + */ + _features: HashMap<ToolboxFeature | UserDefinedToolboxFeature | NullUndefined, FeatureName>; - _featureNames: string[]; + /** + * Current enabled feature names, including only features having `show: true`. + */ + _featureNames: FeatureName[]; render( toolboxModel: ToolboxModel, @@ -74,35 +81,46 @@ class ToolboxView extends ComponentView { const itemSize = +toolboxModel.get('itemSize'); const isVertical = toolboxModel.get('orient') === 'vertical'; const featureOpts = toolboxModel.get('feature') || {}; - const features = this._features || (this._features = {}); + const features = this._features || (this._features = createHashMap()); - const featureNames: string[] = []; - zrUtil.each(featureOpts, function (opt, name) { - featureNames.push(name); + const newFeatureNames: FeatureName[] = []; // Includes both `show: true/false`. + each(featureOpts, function (opt, name) { + newFeatureNames.push(name); }); - (new DataDiffer(this._featureNames || [], featureNames)) + // Diff by feature name. + (new DataDiffer(this._featureNames || [], newFeatureNames)) .add(processFeature) .update(processFeature) - .remove(zrUtil.curry(processFeature, null)) + .remove(curry(processFeature, null)) .execute(); // Keep for diff. - this._featureNames = featureNames; + this._featureNames = filter(newFeatureNames, function (name) { + return features.hasKey(name); + }); + + function processFeature(newIndex: number | NullUndefined, oldIndex?: number | NullUndefined) { + const isDiffAdd = newIndex != null && oldIndex == null; + const isDiffUpdate = newIndex != null && oldIndex != null; + const isDiffRemove = newIndex == null; - function processFeature(newIndex: number, oldIndex?: number) { - const featureName = featureNames[newIndex]; - const oldName = featureNames[oldIndex]; + const featureName = (isDiffAdd || isDiffUpdate) + ? newFeatureNames[newIndex] + : newFeatureNames[oldIndex]; const featureOpt = featureOpts[featureName]; - const featureModel = new Model(featureOpt, toolboxModel, toolboxModel.ecModel) as ToolboxFeatureModel; - let feature: ToolboxFeature | UserDefinedToolboxFeature; + const featureModel = (isDiffAdd || isDiffUpdate) + ? new Model(featureOpt, toolboxModel, ecModel) as ToolboxFeatureModel + : null; + // `.get('show')` Also considered UserDefinedToolboxFeature + const isFeatureShow = featureModel && featureModel.get('show'); - // FIX#11236, merge feature title from MagicType newOption. TODO: consider seriesIndex ? - if (payload && payload.newTitle != null && payload.featureName === featureName) { - featureOpt.title = payload.newTitle; - } + let feature: ToolboxFeature | UserDefinedToolboxFeature; - if (featureName && !oldName) { // Create + if (isDiffAdd) { // DIFF_ADD + if (!isFeatureShow) { + return; + } if (isUserFeatureName(featureName)) { feature = { onclick: featureModel.option.onclick, @@ -116,35 +134,33 @@ class ToolboxView extends ComponentView { } feature = new Feature(); } - features[featureName] = feature; + features.set(featureName, feature); } - else { - feature = features[oldName]; - // If feature does not exist. - if (!feature) { - return; - } + else { // DIFF_UPDATE or DIFF_REMOVE + feature = features.get(featureName); } - feature.uid = getUID('toolbox-feature'); - feature.model = featureModel; - feature.ecModel = ecModel; - feature.api = api; - const isToolboxFeature = feature instanceof ToolboxFeature; - if (!featureName && oldName) { - isToolboxFeature - && (feature as ToolboxFeature).dispose - && (feature as ToolboxFeature).dispose(ecModel, api); + if (isDiffRemove || !isFeatureShow) { + if (isTooltipFeature(feature) && feature.dispose) { + feature.dispose(ecModel, api); + } + features.removeKey(featureName); return; } - if (!featureModel.get('show') || (isToolboxFeature && (feature as ToolboxFeature).unusable)) { - isToolboxFeature - && (feature as ToolboxFeature).remove - && (feature as ToolboxFeature).remove(ecModel, api); - return; + // FIX#11236, merge feature title from MagicType newOption. TODO: consider seriesIndex ? + if (payload && payload.newTitle != null && payload.featureName === featureName) { + // FIXME: ec option should not be modified here. + featureOpt.title = payload.newTitle; } + if (isDiffAdd) { + feature.uid = getUID('toolbox-feature'); + } + feature.model = featureModel; + feature.ecModel = ecModel; + feature.api = api; + createIconPaths(featureModel, feature, featureName); featureModel.setIconStatus = function (this: ToolboxFeatureModel, iconName: string, status: DisplayState) { @@ -157,10 +173,8 @@ class ToolboxView extends ComponentView { } }; - if (feature instanceof ToolboxFeature) { - if (feature.render) { - feature.render(featureModel, ecModel, api, payload); - } + if (isTooltipFeature(feature) && feature.render) { + feature.render(featureModel, ecModel, api, payload); } } @@ -188,14 +202,14 @@ class ToolboxView extends ComponentView { const titles = featureModel.get('title') || {}; let iconsMap: Dictionary<string>; let titlesMap: Dictionary<string>; - if (zrUtil.isString(icons)) { + if (isString(icons)) { iconsMap = {}; iconsMap[featureName] = icons; } else { iconsMap = icons; } - if (zrUtil.isString(titles)) { + if (isString(titles)) { titlesMap = {}; titlesMap[featureName] = titles as string; } @@ -203,7 +217,7 @@ class ToolboxView extends ComponentView { titlesMap = titles; } const iconPaths: ToolboxFeatureModel['iconPaths'] = featureModel.iconPaths = {}; - zrUtil.each(iconsMap, function (iconStr, iconName) { + each(iconsMap, function (iconStr, iconName) { const path = graphic.createIcon( iconStr, {}, @@ -286,7 +300,7 @@ class ToolboxView extends ComponentView { (featureModel.get(['iconStatus', iconName]) === 'emphasis' ? enterEmphasis : leaveEmphasis)(path); group.add(path); - (path as graphic.Path).on('click', zrUtil.bind( + (path as graphic.Path).on('click', bind( feature.onclick, feature, ecModel, api, iconName )); @@ -331,7 +345,7 @@ class ToolboxView extends ComponentView { const textContent = icon.getTextContent(); const emphasisTextState = textContent && textContent.ensureState('emphasis'); // May be background element - if (emphasisTextState && !zrUtil.isFunction(emphasisTextState) && titleText) { + if (emphasisTextState && !isFunction(emphasisTextState) && titleText) { const emphasisTextStyle = emphasisTextState.style || (emphasisTextState.style = {}); const rect = textContain.getBoundingRect( titleText, ZRText.makeFont(emphasisTextStyle) @@ -363,30 +377,20 @@ class ToolboxView extends ComponentView { api: ExtensionAPI, payload: unknown ) { - zrUtil.each(this._features, function (feature) { - feature instanceof ToolboxFeature - && feature.updateView && feature.updateView(feature.model, ecModel, api, payload); - }); - } - - // updateLayout(toolboxModel, ecModel, api, payload) { - // zrUtil.each(this._features, function (feature) { - // feature.updateLayout && feature.updateLayout(feature.model, ecModel, api, payload); - // }); - // }, - - remove(ecModel: GlobalModel, api: ExtensionAPI) { - zrUtil.each(this._features, function (feature) { - feature instanceof ToolboxFeature - && feature.remove && feature.remove(ecModel, api); + each(this._features, function (feature) { + feature + && feature instanceof ToolboxFeature + && feature.updateView + && feature.updateView(feature.model, ecModel, api, payload); }); - this.group.removeAll(); } dispose(ecModel: GlobalModel, api: ExtensionAPI) { - zrUtil.each(this._features, function (feature) { - feature instanceof ToolboxFeature - && feature.dispose && feature.dispose(ecModel, api); + each(this._features, function (feature) { + feature + && feature instanceof ToolboxFeature + && feature.dispose + && feature.dispose(ecModel, api); }); } } @@ -395,4 +399,9 @@ class ToolboxView extends ComponentView { function isUserFeatureName(featureName: string): boolean { return featureName.indexOf('my') === 0; } + +function isTooltipFeature(feature: ToolboxFeature | UserDefinedToolboxFeature): feature is ToolboxFeature { + return feature instanceof ToolboxFeature; +} + export default ToolboxView; diff --git a/src/component/toolbox/feature/DataView.ts b/src/component/toolbox/feature/DataView.ts index def839af5..7f4c506fc 100644 --- a/src/component/toolbox/feature/DataView.ts +++ b/src/component/toolbox/feature/DataView.ts @@ -447,12 +447,8 @@ class DataView extends ToolboxFeature<ToolboxDataViewFeatureOption> { this._dom = root; } - remove(ecModel: GlobalModel, api: ExtensionAPI) { - this._dom && api.getDom().removeChild(this._dom); - } - dispose(ecModel: GlobalModel, api: ExtensionAPI) { - this.remove(ecModel, api); + this._dom && api.getDom().removeChild(this._dom); } static getDefaultOption(ecModel: GlobalModel) { diff --git a/src/component/toolbox/feature/DataZoom.ts b/src/component/toolbox/feature/DataZoom.ts index 8125b6dcc..0c57324de 100644 --- a/src/component/toolbox/feature/DataZoom.ts +++ b/src/component/toolbox/feature/DataZoom.ts @@ -104,13 +104,6 @@ class DataZoomFeature extends ToolboxFeature<ToolboxDataZoomFeatureOption> { handlers[type].call(this); } - remove( - ecModel: GlobalModel, - api: ExtensionAPI - ) { - this._brushController && this._brushController.unmount(); - } - dispose( ecModel: GlobalModel, api: ExtensionAPI diff --git a/src/component/toolbox/featureManager.ts b/src/component/toolbox/featureManager.ts index 5b16acf61..a1f554355 100644 --- a/src/component/toolbox/featureManager.ts +++ b/src/component/toolbox/featureManager.ts @@ -73,9 +73,8 @@ interface ToolboxFeature<Opts extends ToolboxFeatureOption = ToolboxFeatureOptio onclick(ecModel: GlobalModel, api: ExtensionAPI, type: string, event: ZRElementEvent): void dispose?(ecModel: GlobalModel, api: ExtensionAPI): void - remove?(ecModel: GlobalModel, api: ExtensionAPI): void - render(featureModel: ToolboxFeatureModel, model: GlobalModel, api: ExtensionAPI, payload: unknown): void + render?(featureModel: ToolboxFeatureModel, model: GlobalModel, api: ExtensionAPI, payload: unknown): void updateView?(featureModel: ToolboxFeatureModel, model: GlobalModel, api: ExtensionAPI, payload: unknown): void } abstract class ToolboxFeature<Opts extends ToolboxFeatureOption = ToolboxFeatureOption> { @@ -84,11 +83,6 @@ abstract class ToolboxFeature<Opts extends ToolboxFeatureOption = ToolboxFeature model: ToolboxFeatureModel<Opts>; ecModel: GlobalModel; api: ExtensionAPI; - - /** - * If toolbox feature can't be used on some platform. - */ - unusable?: boolean; } export {ToolboxFeature}; diff --git a/test/toolbox-custom.html b/test/toolbox-custom.html index 91eee32b1..0a1b1209f 100644 --- a/test/toolbox-custom.html +++ b/test/toolbox-custom.html @@ -167,6 +167,7 @@ under the License. function createOption() { var option = { + tooltip: {}, xAxis: {}, yAxis: {}, series: { --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
