Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions docs/api-reference/geo-layers/tile-layer.md
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,28 @@ const quadkeyTileLayer = new TileLayer({
});
```

## Methods

### `getTileLoadingState()` {#gettileloadingstate}

Returns granular loading counts for the tiles in the current viewport. Unlike `layer.isLoaded`, which is `true` once all tile requests settle (including failures), this method distinguishes between tiles that loaded successfully, failed, and are still pending.

Returns a `TileLoadingState` object:

| Field | Type | Description |
| --- | --- | --- |
| `total` | `number` | Total tiles in the current viewport |
| `loaded` | `number` | Tiles that loaded successfully (have content) |
| `failed` | `number` | Tiles that settled with no content (404, error, etc.) |
| `pending` | `number` | Tiles still in flight |

```ts
import type {TileLoadingState} from '@deck.gl/geo-layers';

const state: TileLoadingState = tileLayer.getTileLoadingState();
console.log(`${state.loaded}/${state.total} tiles loaded, ${state.failed} failed`);
```

## Source

[modules/geo-layers/src/tile-layer](https://github.com/visgl/deck.gl/tree/master/modules/geo-layers/src/tile-layer)
2 changes: 1 addition & 1 deletion modules/geo-layers/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export type {H3ClusterLayerProps} from './h3-layers/h3-cluster-layer';
export type {H3HexagonLayerProps} from './h3-layers/h3-hexagon-layer';
export type {GreatCircleLayerProps} from './great-circle-layer/great-circle-layer';
export type {S2LayerProps} from './s2-layer/s2-layer';
export type {TileLayerProps, TileLayerPickingInfo} from './tile-layer/tile-layer';
export type {TileLayerProps, TileLayerPickingInfo, TileLoadingState} from './tile-layer/tile-layer';
export type {TripsLayerProps} from './trips-layer/trips-layer';
export type {QuadkeyLayerProps} from './quadkey-layer/quadkey-layer';
export type {TerrainLayerProps} from './terrain-layer/terrain-layer';
Expand Down
20 changes: 20 additions & 0 deletions modules/geo-layers/src/tile-layer/tile-layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ import {GeoJsonLayer} from '@deck.gl/layers';
import {LayersList} from '@deck.gl/core';

import type {TileLoadProps, ZRange} from '../tileset-2d/index';

export type TileLoadingState = {
total: number;
loaded: number;
failed: number;
pending: number;
};
import {
Tileset2D,
Tile2DHeader,
Expand Down Expand Up @@ -222,6 +229,19 @@ export default class TileLayer<DataT = any, ExtraPropsT extends {} = {}> extends
);
}

getTileLoadingState(): TileLoadingState {
const selectedTiles: Tile2DHeader<DataT>[] = this.state?.tileset?.selectedTiles ?? [];
let loaded = 0;
let failed = 0;
let pending = 0;
for (const tile of selectedTiles) {
if (!tile.isLoaded) pending++;
else if (tile.content === null) failed++;
else loaded++;
}
return {total: selectedTiles.length, loaded, failed, pending};
}

shouldUpdateState({changeFlags}): boolean {
return changeFlags.somethingChanged;
}
Expand Down
126 changes: 126 additions & 0 deletions test/modules/geo-layers/get-tile-loading-state.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// deck.gl
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors

import {test, expect} from 'vitest';
import {TileLayer} from '@deck.gl/geo-layers';

const TEST_DATA = [{position: [0, 0]}, {position: [1, 1]}];

test('TileLayer#getTileLoadingState - empty layer', () => {
const layer = new TileLayer({
data: 'https://example.com/tiles/{z}/{x}/{y}',
getTileData: () => null
});

const state = layer.getTileLoadingState();

expect(state.total).toBe(0);
expect(state.loaded).toBe(0);
expect(state.failed).toBe(0);
expect(state.pending).toBe(0);
});

test('TileLayer#getTileLoadingState - all tiles loaded successfully', () => {
const layer = new TileLayer({
id: 'test-layer',
data: 'https://example.com/tiles/{z}/{x}/{y}',
getTileData: async () => TEST_DATA
});

layer.state = {
tileset: {
selectedTiles: [
{isLoaded: true, content: TEST_DATA},
{isLoaded: true, content: TEST_DATA},
{isLoaded: true, content: TEST_DATA}
]
}
} as any;

const state = layer.getTileLoadingState();

expect(state.total).toBe(3);
expect(state.loaded).toBe(3);
expect(state.failed).toBe(0);
expect(state.pending).toBe(0);
});

test('TileLayer#getTileLoadingState - some tiles failed', () => {
const layer = new TileLayer({
id: 'test-layer',
data: 'https://example.com/tiles/{z}/{x}/{y}',
getTileData: async () => TEST_DATA
});

layer.state = {
tileset: {
selectedTiles: [
{isLoaded: true, content: TEST_DATA},
{isLoaded: true, content: null},
{isLoaded: true, content: TEST_DATA},
{isLoaded: true, content: null}
]
}
} as any;

const state = layer.getTileLoadingState();

expect(state.total).toBe(4);
expect(state.loaded).toBe(2);
expect(state.failed).toBe(2);
expect(state.pending).toBe(0);
});

test('TileLayer#getTileLoadingState - tiles still loading', () => {
const layer = new TileLayer({
id: 'test-layer',
data: 'https://example.com/tiles/{z}/{x}/{y}',
getTileData: async () => TEST_DATA
});

layer.state = {
tileset: {
selectedTiles: [
{isLoaded: true, content: TEST_DATA},
{isLoaded: false, content: null},
{isLoaded: false, content: null},
{isLoaded: true, content: null}
]
}
} as any;

const state = layer.getTileLoadingState();

expect(state.total).toBe(4);
expect(state.loaded).toBe(1);
expect(state.failed).toBe(1);
expect(state.pending).toBe(2);
});

test('TileLayer#getTileLoadingState - all tiles failed', () => {
const layer = new TileLayer({
id: 'test-layer',
data: 'https://example.com/tiles/{z}/{x}/{y}',
getTileData: async () => {
throw new Error('Network error');
}
});

layer.state = {
tileset: {
selectedTiles: [
{isLoaded: true, content: null},
{isLoaded: true, content: null},
{isLoaded: true, content: null}
]
}
} as any;

const state = layer.getTileLoadingState();

expect(state.total).toBe(3);
expect(state.loaded).toBe(0);
expect(state.failed).toBe(3);
expect(state.pending).toBe(0);
});
1 change: 1 addition & 0 deletions test/modules/geo-layers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,6 @@ import './tile-3d-layer';
import './terrain-layer.spec';
import './mvt-layer.spec';
import './geohash-layer.spec';
import './get-tile-loading-state.spec';

import './tileset-2d';
Loading