Skip to content
Closed
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
8 changes: 4 additions & 4 deletions modules/geo-layers/src/tileset-2d/tile-2d-header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type {Layer} from '@deck.gl/core';
export type TileLoadDataProps<DataT = any> = {
requestScheduler: RequestScheduler;
getData: (props: TileLoadProps) => Promise<DataT>;
getPriority: (tile: Tile2DHeader<DataT>) => number;
onLoad: (tile: Tile2DHeader<DataT>) => void;
onError: (error: any, tile: Tile2DHeader<DataT>) => void;
};
Expand Down Expand Up @@ -106,6 +107,7 @@ export class Tile2DHeader<DataT = any> {
/* eslint-disable max-statements */
private async _loadData({
getData,
getPriority,
requestScheduler,
onLoad,
onError
Expand All @@ -116,10 +118,8 @@ export class Tile2DHeader<DataT = any> {
this._abortController = new AbortController();
const {signal} = this._abortController;

// @ts-expect-error (2345) Argument of type '(tile: any) => 1 | -1' is not assignable ...
const requestToken = await requestScheduler.scheduleRequest(this, tile => {
return tile.isSelected ? 1 : -1;
});
// @ts-expect-error (2345) loaders.gl's RequestScheduler callback type is too narrow.
const requestToken = await requestScheduler.scheduleRequest(this, getPriority);

if (!requestToken) {
this._isCancelled = true;
Expand Down
38 changes: 38 additions & 0 deletions modules/geo-layers/src/tileset-2d/tileset-2d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,43 @@ export class Tileset2D {

private _getCullBounds = memoize(getCullBounds);

private _getRequestPriority(tile: Tile2DHeader): number {
// RequestScheduler loads lower priority values first.
const distance = this._getTileDistanceSquared(tile);
if (tile.isSelected) {
return distance;
}
if (tile.isVisible) {
return 1e6 + distance;
}
return -1;
}

private _getTileDistanceSquared(tile: Tile2DHeader): number {
const {width, height} = this._viewport || {};
if (!this._viewport || !width || !height) {
return 0;
}

const {bbox} = tile;
const center =
'west' in bbox
? ([(bbox.west + bbox.east) / 2, (bbox.south + bbox.north) / 2] as [number, number])
: ([(bbox.left + bbox.right) / 2, (bbox.top + bbox.bottom) / 2] as [number, number]);

try {
const [x, y] = this._viewport.project(center);
if (Number.isFinite(x) && Number.isFinite(y)) {
const dx = x - width / 2;
const dy = y - height / 2;
return dx * dx + dy * dy;
}
} catch {
// Some viewport/tile combinations are not projectable. Keep them valid but lowest priority.
}
return Number.MAX_SAFE_INTEGER;
}

private _pruneRequests(): void {
const {maxRequests = 0} = this.opts;

Expand Down Expand Up @@ -542,6 +579,7 @@ export class Tileset2D {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
tile.loadData({
getData: this.opts.getTileData,
getPriority: this._getRequestPriority.bind(this),
requestScheduler: this._requestScheduler,
onLoad: this.onTileLoad,
onError: this.opts.onTileError
Expand Down
36 changes: 36 additions & 0 deletions test/modules/geo-layers/tileset-2d/tile-2d-header.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {test, expect} from 'vitest';
import {_Tile2DHeader as Tile2DHeader} from '@deck.gl/geo-layers';
import {RequestScheduler} from '@loaders.gl/loader-utils';

const getPriority = tile => (tile.isSelected ? 1 : -1);

test('Tile2DHeader', async () => {
let onTileLoadCalled = false;
let onTileErrorCalled = false;
Expand All @@ -14,6 +16,7 @@ test('Tile2DHeader', async () => {
let tile2d = new Tile2DHeader({});
await tile2d.loadData({
requestScheduler,
getPriority,
getData: () => 'loaded data',
onLoad: () => (onTileLoadCalled = true),
onError: () => (onTileErrorCalled = true)
Expand All @@ -26,6 +29,7 @@ test('Tile2DHeader', async () => {
tile2d = new Tile2DHeader({});
await tile2d.loadData({
requestScheduler,
getPriority,
getData: () => {
throw new Error('getTileData error');
},
Expand All @@ -44,6 +48,7 @@ test('Tile2DHeader#Cancel request if not selected', async () => {
const requestScheduler = new RequestScheduler({throttleRequests: true, maxRequests: 1});
const opts = {
requestScheduler,
getPriority,
getData: () => tileRequestCount++,
onLoad: () => onTileLoadCalled++,
onError: () => onTileErrorCalled++
Expand All @@ -66,13 +71,43 @@ test('Tile2DHeader#Cancel request if not selected', async () => {
expect(onTileLoadCalled === 1 && onTileErrorCalled === 0, 'Callbacks invoked').toBeTruthy();
});

test('Tile2DHeader#request priority', async () => {
const requestOrder: string[] = [];
const requestScheduler = new RequestScheduler({throttleRequests: true, maxRequests: 1});
const opts = {
requestScheduler,
getPriority: tile => (tile.id === 'center' ? 0 : 10),
getData: ({id}) => {
requestOrder.push(id);
return id;
},
onLoad: () => {},
onError: () => {}
};

const edgeTile = new Tile2DHeader({});
edgeTile.id = 'edge';
edgeTile.isSelected = true;
const centerTile = new Tile2DHeader({});
centerTile.id = 'center';
centerTile.isSelected = true;

const edgeLoader = edgeTile.loadData(opts);
const centerLoader = centerTile.loadData(opts);
await edgeLoader;
await centerLoader;

expect(requestOrder, 'lower request priority values load first').toEqual(['center', 'edge']);
});

test('Tile2DHeader#abort', async () => {
const requestScheduler = new RequestScheduler({throttleRequests: true, maxRequests: 1});
let onTileLoadCalled = false;
let onTileErrorCalled = false;

const opts = {
requestScheduler,
getPriority,
getData: () => null,
onLoad: () => (onTileLoadCalled = true),
onError: () => (onTileErrorCalled = true)
Expand Down Expand Up @@ -104,6 +139,7 @@ test('Tile2DHeader#reload', async () => {
let onTileErrorCalled = 0;
const opts = {
requestScheduler,
getPriority,
onLoad: () => onTileLoadCalled++,
onError: () => onTileErrorCalled++
};
Expand Down
Loading