Custom source enhancement
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 12.4k
- Forks
- 2.4k
- PR merge metrics
- No merged PRs in 30d
Description
## Motivation
Currently, the custom data source of mapbox only supports Raster type, Judging by the following logic:
```js
function isRaster(data: any): boolean {
return data instanceof ImageData ||
data instanceof HTMLCanvasElement ||
data instanceof ImageBitmap ||
data instanceof HTMLImageElement;
}
```
This is sufficient in most cases, but it brings some limitations when we need some non-standard raster data,such as TIFF/netcdf/geojson
## Design Alternatives
Based on the above objectives, if we can rewrite the loadTile, loadTileData of [custom_source](https://github1s.com/mapbox/mapbox-gl-js/blob/HEAD/src/source/custom_source.js), it will bring better scalability.The relevant logic is implemented by the user implementation, custom_source can support parsing of multiple data types
## Design
### Mock-Up
### Concepts
### Implementation
loadTileData:
```diff
loadTileData(tile: Tile, data: T): void {
- tile.setTexture((data: any), this._map.painter);
+ if (this._implementation.loadTileData) {
+ this._implementation.loadTileData(tile, data, this._map.painter);
+ } else {
+ // Only raster data supported at the moment
+ tile.setTexture((data: any), this._map.painter);
+ }
}
```
loadTile:
```diff
loadTile(tile: Tile, callback: Callback): void {
+ if (this._implementation.loadTileOverride) {
+ this._implementation.loadTileOverride(tile, callback, this._map);
+ } else {
const {x, y, z} = tile.tileID.canonical;
const controller = new window.AbortController();
const signal = controller.signal;
// $FlowFixMe[prop-missing]
tile.request = Promise
.resolve(this._implementation.loadTile({x, y, z}, {signal}))
.then(tileLoaded.bind(this))
.catch(error => {
// silence AbortError
if (error.code === 20) return;
tile.state = 'errored';
callback(error);
});
// $FlowFixMe[prop-missing]
tile.request.cancel = () => controller.abort();
// $FlowFixMe[missing-this-annot]
function tileLoaded(data: ?T) {
delete tile.request;
if (tile.aborted) {
tile.state = 'unloaded';
return callback(null);
}
// If the implementation returned `undefined` as tile data,
// mark the tile as `errored` to indicate that we have no data for it.
// A map will render an overscaled parent tile in the tile’s space.
if (data === undefined) {
tile.state = 'errored';
return callback(null);
}
// If the implementation returned `null` as tile data,
// mark the tile as `loaded` and use an an empty image as tile data.
// A map will render nothing in the tile’s space.
if (data === null) {
const emptyImage = {width: this.tileSize, height: this.tileSize, data: null};
this.loadTileData(tile, (emptyImage: any));
tile.state = 'loaded';
return callback(null);
}
if (!isRaster(data)) {
tile.state = 'errored';
return callback(new Error(`Can't infer data type for ${this.id}, only raster data supported at the moment`));
}
this.loadTileData(tile, data);
tile.state = 'loaded';
callback(null);
}
+ }
}
```
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with src/source/custom_source.js and read the existing loadTile, loadTileData, and isRaster flow. Trace how custom source implementations pass tile data into rendering, then define and verify the extension points for user-controlled loading and tile-data handling so non-raster data can be supported without breaking existing raster behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- frontend, web-dev
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100