@@ -59,6 +59,7 @@ import {
5959} from './labelLayoutHelper' ;
6060import { labelInner , animateLabelValue } from './labelStyle' ;
6161import { normalizeRadian } from 'zrender/src/contain/util' ;
62+ import { throttle } from '../util/throttle' ;
6263
6364interface LabelDesc {
6465 label : ZRText
@@ -194,10 +195,127 @@ function extendWithKeys(target: Dictionary<any>, source: Dictionary<any>, keys:
194195
195196const LABEL_LAYOUT_PROPS = [ 'x' , 'y' , 'rotation' ] ;
196197
198+ /**
199+ * Emphasis manager for handling label emphasis state changes
200+ */
201+ class EmphasisManager {
202+ // eslint-disable-next-line no-undef
203+ private currentEmphasisLabels : Set < Element > = new Set ( ) ;
204+ private labelsNeedsHideOverlap : LabelLayoutWithGeometry [ ] = [ ] ;
205+ // eslint-disable-next-line no-undef
206+ private originalStates : Map < Element , boolean > = new Map ( ) ;
207+
208+ setLabelsNeedsHideOverlap ( labels : LabelLayoutWithGeometry [ ] ) : void {
209+ this . clear ( ) ;
210+ if ( labels . length === 0 ) {
211+ return ;
212+ }
213+
214+ this . labelsNeedsHideOverlap = labels ;
215+
216+ // Record original ignore states only when needed
217+ labels . forEach ( item => {
218+ this . originalStates . set ( item . label , item . label . ignore ) ;
219+ if ( item . labelLine ) {
220+ this . originalStates . set ( item . labelLine , item . labelLine . ignore ) ;
221+ }
222+ } ) ;
223+ }
224+
225+ handleEmphasisChange ( targetLabel : Element , isEnteringEmphasis : boolean ) : void {
226+ // Early return if no labels need hideOverlap processing
227+ if ( this . labelsNeedsHideOverlap . length === 0 ) {
228+ return ;
229+ }
230+
231+ if ( isEnteringEmphasis ) {
232+ this . currentEmphasisLabels . add ( targetLabel ) ;
233+ }
234+ else {
235+ this . currentEmphasisLabels . delete ( targetLabel ) ;
236+ }
237+
238+ if ( this . currentEmphasisLabels . size === 0 ) {
239+ // No emphasis labels, restore original state
240+ this . restoreOriginalState ( ) ;
241+ }
242+ else {
243+ // Re-sort with emphasis labels first and call hideOverlap
244+ this . reorderAndHideOverlap ( ) ;
245+ }
246+ }
247+
248+ private reorderAndHideOverlap = throttle ( ( ) => {
249+ if ( this . labelsNeedsHideOverlap . length === 0 ) {
250+ return ;
251+ }
252+
253+ // Create a copy for reordering
254+ const reorderedLabels = [ ...this . labelsNeedsHideOverlap ] ;
255+
256+ // Sort: emphasis labels first, then by original priority
257+ reorderedLabels . sort ( ( a , b ) => {
258+ const aIsEmphasis = this . currentEmphasisLabels . has ( a . label ) ? 1 : 0 ;
259+ const bIsEmphasis = this . currentEmphasisLabels . has ( b . label ) ? 1 : 0 ;
260+
261+ // Emphasis labels come first
262+ if ( aIsEmphasis !== bIsEmphasis ) {
263+ return bIsEmphasis - aIsEmphasis ;
264+ }
265+
266+ // Then by original priority
267+ return ( ( b . suggestIgnore ? 1 : 0 ) - ( a . suggestIgnore ? 1 : 0 ) )
268+ || ( b . priority - a . priority ) ;
269+ } ) ;
270+
271+ // First restore all to show state
272+ reorderedLabels . forEach ( item => {
273+ item . label . ignore = false ;
274+ const emphasisState = item . label . ensureState ( 'emphasis' ) ;
275+ emphasisState . ignore = false ;
276+
277+ if ( item . labelLine ) {
278+ item . labelLine . ignore = false ;
279+ const lineEmphasisState = item . labelLine . ensureState ( 'emphasis' ) ;
280+ lineEmphasisState . ignore = false ;
281+ }
282+ } ) ;
283+
284+ // Call hideOverlap with isOrdered = true
285+ hideOverlap ( reorderedLabels , true ) ;
286+ } , 16 , true ) ;
287+
288+ private restoreOriginalState = throttle ( ( ) => {
289+ this . labelsNeedsHideOverlap . forEach ( item => {
290+ const originalIgnore = this . originalStates . get ( item . label ) ?? false ;
291+ item . label . ignore = originalIgnore ;
292+
293+ // For emphasis state, use the original hideOverlap logic
294+ const emphasisState = item . label . ensureState ( 'emphasis' ) ;
295+ emphasisState . ignore = originalIgnore ;
296+
297+ if ( item . labelLine ) {
298+ const originalLineIgnore = this . originalStates . get ( item . labelLine ) ?? false ;
299+ item . labelLine . ignore = originalLineIgnore ;
300+
301+ const lineEmphasisState = item . labelLine . ensureState ( 'emphasis' ) ;
302+ lineEmphasisState . ignore = originalLineIgnore ;
303+ }
304+ } ) ;
305+ } , 16 , true ) ;
306+
307+ clear ( ) : void {
308+ this . currentEmphasisLabels . clear ( ) ;
309+ this . labelsNeedsHideOverlap = [ ] ;
310+ this . originalStates . clear ( ) ;
311+ }
312+ }
313+
197314class LabelManager {
198315
199316 private _labelList : LabelDesc [ ] = [ ] ;
200317 private _chartViewList : ChartView [ ] = [ ] ;
318+ private _emphasisManager : EmphasisManager = new EmphasisManager ( ) ;
201319
202320 constructor ( ) { }
203321
@@ -323,6 +441,32 @@ class LabelManager {
323441 // Can only attach the text on the element with dataIndex
324442 if ( textEl && ! ( textEl as ECElement ) . disableLabelLayout ) {
325443 this . _addLabel ( ecData . dataIndex , ecData . dataType , seriesModel , textEl , layoutOption ) ;
444+ // Add emphasis state change listener for hideOverlap labels
445+ const resolvedLayoutOption = isFunction ( layoutOption ) ? null : layoutOption ;
446+ if ( resolvedLayoutOption && resolvedLayoutOption . hideOverlap ) {
447+ const hostEl = child as ECElement ;
448+ const originalOnHoverStateChange = hostEl . onHoverStateChange ;
449+ const labelManager = this ;
450+
451+ hostEl . onHoverStateChange = function ( toState : string ) {
452+ // Call original handler first
453+ if ( originalOnHoverStateChange ) {
454+ originalOnHoverStateChange . call ( this , toState ) ;
455+ }
456+
457+ // Handle emphasis state change for hideOverlap labels
458+ if ( toState === 'emphasis' || toState === 'normal' ) {
459+ // Find the label element - could be textEl or child itself
460+ const labelElement = textEl || this ;
461+
462+ // Use EmphasisManager to handle the state change
463+ labelManager . _emphasisManager . handleEmphasisChange (
464+ labelElement ,
465+ toState === 'emphasis'
466+ ) ;
467+ }
468+ } ;
469+ }
326470 }
327471 } ) ;
328472 }
@@ -466,6 +610,7 @@ class LabelManager {
466610
467611 restoreIgnore ( labelsNeedsHideOverlap ) ;
468612 hideOverlap ( labelsNeedsHideOverlap ) ;
613+ this . _emphasisManager . setLabelsNeedsHideOverlap ( labelsNeedsHideOverlap ) ;
469614 }
470615
471616 /**
0 commit comments