@@ -57,6 +57,7 @@ class SourceCache extends Evented {
57
57
_isIdRenderable: ( id : string , symbolLayer ? : boolean ) => boolean ;
58
58
used: boolean ;
59
59
_state: SourceFeatureState ;
60
+ _loadedParentTiles: { [ string ] : ?Tile } ;
60
61
61
62
static maxUnderzooming: number ;
62
63
static maxOverzooming: number ;
@@ -93,6 +94,7 @@ class SourceCache extends Evented {
93
94
this . _timers = { } ;
94
95
this . _cacheTimers = { } ;
95
96
this . _maxTileCacheSize = null ;
97
+ this . _loadedParentTiles = { } ;
96
98
97
99
this . _coveredTiles = { } ;
98
100
this . _state = new SourceFeatureState ( ) ;
@@ -367,19 +369,32 @@ class SourceCache extends Evented {
367
369
* Find a loaded parent of the given tile (up to minCoveringZoom)
368
370
*/
369
371
findLoadedParent ( tileID : OverscaledTileID , minCoveringZoom : number ) : ?Tile {
372
+ if ( tileID . key in this . _loadedParentTiles ) {
373
+ const parent = this . _loadedParentTiles [ tileID . key ] ;
374
+ if ( parent && parent . tileID . overscaledZ >= minCoveringZoom ) {
375
+ return parent ;
376
+ } else {
377
+ return null ;
378
+ }
379
+ }
370
380
for ( let z = tileID . overscaledZ - 1 ; z >= minCoveringZoom ; z -- ) {
371
- const parentKey = tileID . calculateScaledKey ( z , true ) ;
372
- const tile = this . _tiles [ parentKey ] ;
373
- if ( tile && tile . hasData ( ) ) {
381
+ const parentTileID = tileID . scaledTo ( z ) ;
382
+ const tile = this . _getLoadedTile ( parentTileID ) ;
383
+ if ( tile )
374
384
return tile ;
375
- }
376
- // TileCache ignores wrap in lookup.
377
- const parentWrappedKey = tileID . calculateScaledKey ( z , false ) ;
378
- const cachedTile = this . _cache . getByKey ( parentWrappedKey ) ;
379
- if ( cachedTile ) return cachedTile ;
380
385
}
381
386
}
382
387
388
+ _getLoadedTile ( tileID : OverscaledTileID ) : ?Tile {
389
+ const tile = this . _tiles [ tileID . key ] ;
390
+ if ( tile && tile . hasData ( ) ) {
391
+ return tile ;
392
+ }
393
+ // TileCache ignores wrap in lookup.
394
+ const cachedTile = this . _cache . getByKey ( tileID . wrapped ( ) . key ) ;
395
+ return cachedTile ;
396
+ }
397
+
383
398
/**
384
399
* Resizes the tile cache based on the current viewport's size
385
400
* or the maxTileCacheSize option passed during map creation
@@ -537,6 +552,40 @@ class SourceCache extends Evented {
537
552
this . _removeTile ( tileID ) ;
538
553
}
539
554
}
555
+
556
+ // Construct a cache of loaded parents
557
+ this . _loadedParentTiles = { } ;
558
+
559
+ for ( const tile of ( Object . values ( this . _tiles ) : any ) ) {
560
+ const path = [ ] ;
561
+ let parentTile : ?Tile ;
562
+ let currentId = tile . tileID ;
563
+
564
+ // Find the closest loaded ancestor by traversing the tile tree towards the root and
565
+ // caching results along the way
566
+ while ( currentId . overscaledZ > 0 ) {
567
+ const parentId = currentId . scaledTo ( currentId . overscaledZ - 1 ) ;
568
+ path . push ( currentId . key ) ;
569
+
570
+ // Do we have a cached result from previous traversals?
571
+ if ( parentId . key in this . _loadedParentTiles ) {
572
+ parentTile = this . _loadedParentTiles [ parentId . key ] ;
573
+ break ;
574
+ }
575
+
576
+ parentTile = this . _getLoadedTile ( parentId ) ;
577
+ if ( parentTile ) {
578
+ break;
579
+ }
580
+
581
+ currentId = parentId ;
582
+ }
583
+
584
+ // Cache the result of this traversal to all newly visited tiles
585
+ for ( let i = 0 ; i < path . length ; i ++ ) {
586
+ this . _loadedParentTiles [ path [ i ] ] = parentTile ;
587
+ }
588
+ }
540
589
}
541
590
542
591
releaseSymbolFadeTiles ( ) {
0 commit comments