@@ -99,21 +99,23 @@ export const defaultOptions: Options = {
99
99
100
100
// References to the favicons that we need to track in order to reset and update the counters
101
101
const current : {
102
+ canvas : HTMLCanvasElement | null
103
+ context : CanvasRenderingContext2D | null
102
104
favicons : Favicon [ ] | null
103
105
bestFavicon : BestFavicon
106
+ bestFaviconImage : HTMLImageElement | null
104
107
value : Value
105
108
options : Options
106
109
} = {
110
+ canvas : null ,
111
+ context : null ,
107
112
favicons : null ,
108
113
bestFavicon : null ,
114
+ bestFaviconImage : null ,
109
115
value : 0 ,
110
116
options : defaultOptions ,
111
117
}
112
118
113
- // Setup the source canvas element which we use to generate the favicon's data-url's from
114
- let canvas : HTMLCanvasElement | null = null
115
- let context : CanvasRenderingContext2D | null = null
116
-
117
119
// Update favicon
118
120
const setFavicon = ( url : string ) => {
119
121
if ( ! url ) {
@@ -138,33 +140,36 @@ const setFavicon = (url: string) => {
138
140
}
139
141
140
142
// Draw the favicon
141
- const drawFavicon = ( value : Value , options : Options ) => {
142
- const image = document . createElement ( 'img' )
143
- image . onload = ( ) => {
144
- if ( ! canvas ) {
145
- return
146
- }
147
-
148
- // Draw image in canvas
149
- context ! . clearRect ( 0 , 0 , size , size )
150
- context ! . drawImage ( image , 0 , 0 , image . width , image . height , 0 , 0 , size , size )
151
-
152
- // Draw bubble over the top
153
- drawBubble ( context ! , value , options )
154
-
155
- // Refresh tag in page
156
- setFavicon ( canvas . toDataURL ( ) )
143
+ const drawFavicon = (
144
+ image : HTMLImageElement ,
145
+ value : Value ,
146
+ options : Options
147
+ ) => {
148
+ if ( ! current . canvas || ! current . context ) {
149
+ return
157
150
}
158
151
159
- // Load image of best favicon so we can manipulate it
160
- if ( current . bestFavicon ) {
161
- // Allow cross origin resource requests if the image is not a data:uri
162
- if ( ! current . bestFavicon . href . match ( / ^ d a t a / ) ) {
163
- image . crossOrigin = 'anonymous'
164
- }
165
-
166
- image . src = current . bestFavicon . href
167
- }
152
+ // Clear old canvas
153
+ current . context . clearRect ( 0 , 0 , size , size )
154
+
155
+ // Draw new image
156
+ current . context . drawImage (
157
+ image ,
158
+ 0 ,
159
+ 0 ,
160
+ image . width ,
161
+ image . height ,
162
+ 0 ,
163
+ 0 ,
164
+ size ,
165
+ size
166
+ )
167
+
168
+ // Draw bubble on the top
169
+ drawBubble ( current . context , value , options )
170
+
171
+ // Refresh tag in page
172
+ setFavicon ( current . canvas . toDataURL ( ) )
168
173
}
169
174
170
175
// Draws the bubble on the canvas
@@ -232,14 +237,16 @@ const drawBubble = (
232
237
}
233
238
234
239
export function isAvailable ( ) {
235
- if ( ! context ) {
236
- canvas = document . createElement ( 'canvas' )
240
+ if ( ! current . context ) {
241
+ const canvas = document . createElement ( 'canvas' )
237
242
canvas . width = size
238
243
canvas . height = size
239
- context = canvas . getContext ? canvas . getContext ( '2d' ) : null
244
+
245
+ current . canvas = canvas
246
+ current . context = canvas . getContext ? canvas . getContext ( '2d' ) : null
240
247
}
241
248
242
- return ! ! context && ! ! getBestFavicon ( )
249
+ return ! ! current . context && ! ! getBestFavicon ( )
243
250
}
244
251
245
252
export function set ( value : Value , options ?: Partial < Options > ) {
@@ -252,11 +259,47 @@ export function set(value: Value, options?: Partial<Options>) {
252
259
}
253
260
254
261
// Remember favicons
255
- current . bestFavicon = current . bestFavicon || getBestFavicon ( )
256
- current . favicons = current . favicons || getFavicons ( )
262
+ if ( ! current . bestFavicon ) {
263
+ const bestFavicon = getBestFavicon ( )
264
+
265
+ if ( bestFavicon ) {
266
+ const bestFaviconImage = document . createElement ( 'img' )
267
+ bestFaviconImage . width = size
268
+ bestFaviconImage . height = size
269
+
270
+ // Allow cross origin resource requests if the image is not a data:uri
271
+ if ( ! bestFavicon . href . match ( / ^ d a t a / ) ) {
272
+ bestFaviconImage . crossOrigin = 'anonymous'
273
+ }
274
+
275
+ // Load image
276
+ bestFaviconImage . src = bestFavicon . href
277
+
278
+ // Store for next time
279
+ current . bestFavicon = bestFavicon
280
+ current . bestFaviconImage = bestFaviconImage
281
+ }
282
+ }
283
+ if ( ! current . favicons ) {
284
+ current . favicons = getFavicons ( )
285
+ }
257
286
258
287
// Draw icon
259
- drawFavicon ( current . value , current . options )
288
+ if ( ! current . bestFaviconImage ) {
289
+ return false
290
+ }
291
+
292
+ // If we have the image, we can draw immediately
293
+ if ( current . bestFaviconImage . complete ) {
294
+ drawFavicon ( current . bestFaviconImage , current . value , current . options )
295
+ return true
296
+ }
297
+
298
+ // Otherwise we will wait for the load event
299
+ current . bestFaviconImage . addEventListener ( 'load' , function ( ) {
300
+ drawFavicon ( this , current . value , current . options )
301
+ } )
302
+
260
303
return true
261
304
}
262
305
@@ -279,5 +322,6 @@ export function clear() {
279
322
}
280
323
current . favicons = null
281
324
current . bestFavicon = null
325
+ current . bestFaviconImage = null
282
326
}
283
327
}
0 commit comments