@@ -43,6 +43,9 @@ export interface InteractionCallbacks {
4343
4444 /** Called when hover state over event changes. Returns true if over an event. */
4545 onHoverChange ?: ( isOverEvent : boolean ) => void ;
46+
47+ /** Called when mouse leaves the canvas. */
48+ onMouseLeave ?: ( ) => void ;
4649}
4750
4851export class TimelineInteractionHandler {
@@ -124,8 +127,8 @@ export class TimelineInteractionHandler {
124127 const mouseUpHandler = this . handleMouseUp . bind ( this ) ;
125128
126129 this . canvas . addEventListener ( 'mousedown' , mouseDownHandler ) ;
127- document . addEventListener ( 'mousemove' , mouseMoveHandler ) ;
128- document . addEventListener ( 'mouseup' , mouseUpHandler ) ;
130+ this . canvas . addEventListener ( 'mousemove' , mouseMoveHandler ) ;
131+ this . canvas . addEventListener ( 'mouseup' , mouseUpHandler ) ;
129132 this . registerBoundHandler ( 'mousedown' , mouseDownHandler ) ;
130133 this . registerBoundHandler ( 'mousemove' , mouseMoveHandler ) ;
131134 this . registerBoundHandler ( 'mouseup' , mouseUpHandler ) ;
@@ -148,6 +151,11 @@ export class TimelineInteractionHandler {
148151 const clickHandler = this . handleClick . bind ( this ) ;
149152 this . canvas . addEventListener ( 'click' , clickHandler ) ;
150153 this . registerBoundHandler ( 'click' , clickHandler ) ;
154+
155+ // Mouse leave for hiding tooltips
156+ const mouseLeaveHandler = this . handleMouseLeave . bind ( this ) ;
157+ this . canvas . addEventListener ( 'mouseleave' , mouseLeaveHandler ) ;
158+ this . registerBoundHandler ( 'mouseleave' , mouseLeaveHandler ) ;
151159 }
152160
153161 /**
@@ -170,10 +178,10 @@ export class TimelineInteractionHandler {
170178 this . canvas . removeEventListener ( 'mousedown' , mouseDownHandler ) ;
171179 }
172180 if ( mouseMoveHandler ) {
173- document . removeEventListener ( 'mousemove' , mouseMoveHandler ) ;
181+ this . canvas . removeEventListener ( 'mousemove' , mouseMoveHandler ) ;
174182 }
175183 if ( mouseUpHandler ) {
176- document . removeEventListener ( 'mouseup' , mouseUpHandler ) ;
184+ this . canvas . removeEventListener ( 'mouseup' , mouseUpHandler ) ;
177185 }
178186
179187 // Remove touch event listeners
@@ -197,6 +205,11 @@ export class TimelineInteractionHandler {
197205 this . canvas . removeEventListener ( 'click' , clickHandler ) ;
198206 }
199207
208+ const mouseLeaveHandler = this . boundHandlers . get ( 'mouseleave' ) ;
209+ if ( mouseLeaveHandler ) {
210+ this . canvas . removeEventListener ( 'mouseleave' , mouseLeaveHandler ) ;
211+ }
212+
200213 this . boundHandlers . clear ( ) ;
201214 }
202215
@@ -366,6 +379,15 @@ export class TimelineInteractionHandler {
366379 }
367380 }
368381
382+ /**
383+ * Handle mouse leave - notify when cursor exits canvas.
384+ */
385+ private handleMouseLeave ( _event : MouseEvent ) : void {
386+ if ( this . callbacks . onMouseLeave ) {
387+ this . callbacks . onMouseLeave ( ) ;
388+ }
389+ }
390+
369391 // ============================================================================
370392 // TOUCH EVENT HANDLERS
371393 // ============================================================================
0 commit comments