@@ -36,28 +36,41 @@ function cubicBezier(t: number, p1x: number, p1y: number, p2x: number, p2y: numb
36
36
return sampleCurveY ( solveCurveX ( t ) )
37
37
}
38
38
39
- export function highlightElement ( element : HTMLElement | null ) : void {
39
+ // Shared canvas element for all highlight operations
40
+ let sharedCanvas : HTMLCanvasElement | null = null
41
+ let currentAnimationId : number | null = null
42
+
43
+ export function highlightElement ( element : HTMLElement | null , colorString = "255, 165, 0" ) : void {
40
44
if ( ! element ) return
41
45
46
+ // Cancel any ongoing animation
47
+ if ( currentAnimationId !== null ) {
48
+ cancelAnimationFrame ( currentAnimationId )
49
+ currentAnimationId = null
50
+ }
51
+
42
52
// Get element's bounding rectangle
43
53
const rect : DOMRect = element . getBoundingClientRect ( )
44
54
const padding = 10 // Extra space for shadow effect
45
55
46
- // Create canvas
47
- const canvas : HTMLCanvasElement = document . createElement ( "canvas" )
48
- canvas . style . position = "absolute"
49
- canvas . style . top = `${ rect . top + window . scrollY - padding } px`
50
- canvas . style . left = `${ rect . left + window . scrollX - padding } px`
51
- canvas . width = rect . width + padding * 2
52
- canvas . height = rect . height + padding * 2
56
+ // Create or reuse canvas
57
+ if ( ! sharedCanvas ) {
58
+ sharedCanvas = document . createElement ( "canvas" )
59
+ sharedCanvas . style . position = "absolute"
60
+ sharedCanvas . style . pointerEvents = "none"
61
+ sharedCanvas . style . zIndex = "999999"
62
+ sharedCanvas . id = "follow-highlight-canvas"
63
+ document . body . append ( sharedCanvas )
64
+ }
53
65
54
- canvas . style . pointerEvents = "none"
55
- canvas . style . zIndex = "999999"
56
- document . body . append ( canvas )
66
+ // Update canvas position and size
67
+ sharedCanvas . style . top = `${ rect . top + window . scrollY - padding } px`
68
+ sharedCanvas . style . left = `${ rect . left + window . scrollX - padding } px`
69
+ sharedCanvas . width = rect . width + padding * 2
70
+ sharedCanvas . height = rect . height + padding * 2
57
71
58
- const ctx : CanvasRenderingContext2D = canvas . getContext ( "2d" ) !
72
+ const ctx : CanvasRenderingContext2D = sharedCanvas . getContext ( "2d" ) !
59
73
if ( ! ctx ) {
60
- canvas . remove ( )
61
74
return
62
75
}
63
76
@@ -105,8 +118,11 @@ export function highlightElement(element: HTMLElement | null): void {
105
118
const segmentT : number = ( t - segmentIndex * segmentDuration ) / segmentDuration
106
119
107
120
if ( segmentIndex >= keyframes . length - 1 ) {
108
- // Animation complete, remove canvas
109
- canvas . remove ( )
121
+ // Animation complete, hide canvas
122
+ if ( sharedCanvas ) {
123
+ sharedCanvas . style . display = "none"
124
+ }
125
+ currentAnimationId = null
110
126
return
111
127
}
112
128
@@ -132,11 +148,11 @@ export function highlightElement(element: HTMLElement | null): void {
132
148
)
133
149
134
150
// Clear canvas
135
- ctx . clearRect ( 0 , 0 , canvas . width , canvas . height )
151
+ ctx . clearRect ( 0 , 0 , sharedCanvas ! . width , sharedCanvas ! . height )
136
152
137
153
// Draw shadow (approximated as thick border with rounded corners)
138
154
if ( shadowWidth > 0 ) {
139
- ctx . strokeStyle = `rgba(255, 165, 0 , ${ shadowOpacity } )` // Orange color
155
+ ctx . strokeStyle = `rgba(${ colorString } , ${ shadowOpacity } )` // Orange color
140
156
ctx . lineWidth = shadowWidth
141
157
ctx . beginPath ( )
142
158
ctx . roundRect (
@@ -151,7 +167,7 @@ export function highlightElement(element: HTMLElement | null): void {
151
167
152
168
// Draw outline (with rounded corners)
153
169
if ( outlineWidth > 0 ) {
154
- ctx . strokeStyle = `rgba(255, 165, 0 , ${ outlineOpacity } )`
170
+ ctx . strokeStyle = `rgba(${ colorString } , ${ outlineOpacity } )`
155
171
ctx . lineWidth = outlineWidth
156
172
ctx . beginPath ( )
157
173
ctx . roundRect (
@@ -165,11 +181,19 @@ export function highlightElement(element: HTMLElement | null): void {
165
181
}
166
182
167
183
if ( t < 1 ) {
168
- requestAnimationFrame ( animate )
184
+ currentAnimationId = requestAnimationFrame ( animate )
169
185
} else {
170
- canvas . remove ( )
186
+ if ( sharedCanvas ) {
187
+ sharedCanvas . style . display = "none"
188
+ }
189
+ currentAnimationId = null
171
190
}
172
191
}
173
192
174
- requestAnimationFrame ( animate )
193
+ // Show canvas before starting animation
194
+ if ( sharedCanvas ) {
195
+ sharedCanvas . style . display = "block"
196
+ }
197
+
198
+ currentAnimationId = requestAnimationFrame ( animate )
175
199
}
0 commit comments