From 821e69b2c5444ea762c2c3058727fa909dd61509 Mon Sep 17 00:00:00 2001 From: Murtuza Zabuawala Date: Thu, 9 Jul 2026 18:25:58 +0530 Subject: [PATCH] fix(toolbox): fix updateView and dispose silently no-oping on toolbox features ToolboxView._features is a zrender HashMap (created via createHashMap()), which stores entries in an internal native Map. zrUtil.each() iterates it as a plain object, so the callbacks in updateView and dispose never received any feature and both methods silently did nothing. As a result feature dispose was never called, leaking each feature's resources whenever the view was disposed. For the dataZoom feature this leaks its BrushController: the controller's zr mouse handlers stay bound, and each leaked controller paints its own semi-transparent cover on drag-to-zoom, so the selection overlay gets progressively darker after every dispose/render cycle. Feature updateView was likewise never invoked on chart updates. Iterate with the HashMap's own .each() instead. --- src/component/toolbox/ToolboxView.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/component/toolbox/ToolboxView.ts b/src/component/toolbox/ToolboxView.ts index 8b7c82421a..250cf3c953 100644 --- a/src/component/toolbox/ToolboxView.ts +++ b/src/component/toolbox/ToolboxView.ts @@ -377,7 +377,9 @@ class ToolboxView extends ComponentView { api: ExtensionAPI, payload: unknown ) { - each(this._features, function (feature) { + // `_features` is a `HashMap` rather than a plain object, so it has to be + // iterated with its own `each` method - `zrUtil.each` cannot traverse it. + this._features && this._features.each(function (feature) { feature && feature instanceof ToolboxFeature && feature.updateView @@ -386,7 +388,7 @@ class ToolboxView extends ComponentView { } dispose(ecModel: GlobalModel, api: ExtensionAPI) { - each(this._features, function (feature) { + this._features && this._features.each(function (feature) { feature && feature instanceof ToolboxFeature && feature.dispose