Skip to content

Commit

Permalink
CARTO: Initial implementation of v9 API (#8167)
Browse files Browse the repository at this point in the history
  • Loading branch information
felixpalmer authored and Pessimistress committed Oct 5, 2023
1 parent 13f8ab3 commit a2b5690
Show file tree
Hide file tree
Showing 33 changed files with 1,125 additions and 320 deletions.
12 changes: 4 additions & 8 deletions modules/carto/src/api/layer-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ import moment from 'moment-timezone';
import {Accessor, Layer, _ConstructorOf as ConstructorOf} from '@deck.gl/core';
import {CPUGridLayer, HeatmapLayer, HexagonLayer} from '@deck.gl/aggregation-layers';
import {GeoJsonLayer} from '@deck.gl/layers';
import {H3HexagonLayer, MVTLayer} from '@deck.gl/geo-layers';
import {H3HexagonLayer} from '@deck.gl/geo-layers';

import CartoTileLayer from '../layers/carto-tile-layer';
import H3TileLayer from '../layers/h3-tile-layer';
import QuadbinTileLayer from '../layers/quadbin-tile-layer';
import RasterTileLayer from '../layers/raster-tile-layer';
import VectorTileLayer from '../layers/vector-tile-layer';
import {MapType, TILE_FORMATS, TileFormat} from './maps-api-common';
import {assert, createBinaryProxy} from '../utils';
import {
Expand Down Expand Up @@ -204,7 +204,7 @@ export function layerFromTileDataset(
formatTiles: TileFormat | null = TILE_FORMATS.MVT,
scheme: string,
type?: MapType
): typeof CartoTileLayer | typeof H3TileLayer | typeof MVTLayer | typeof QuadbinTileLayer {
): typeof VectorTileLayer | typeof H3TileLayer | typeof QuadbinTileLayer {
if (type === 'raster') {
return RasterTileLayer;
}
Expand All @@ -214,12 +214,8 @@ export function layerFromTileDataset(
if (scheme === 'quadbin') {
return QuadbinTileLayer;
}
if (formatTiles === 'mvt') {
return MVTLayer;
}

// formatTiles === BINARY|JSON|GEOJSON
return CartoTileLayer;
return VectorTileLayer;
}

function getTileLayer(dataset: MapDataset, basePropMap) {
Expand Down
1 change: 0 additions & 1 deletion modules/carto/src/api/maps-api-common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ export const GEO_COLUMN_SUPPORT: MapType[] = [MAP_TYPES.QUERY, MAP_TYPES.TABLE];
// AVAILABLE FORMATS
export const FORMATS = {
GEOJSON: 'geojson',
NDJSON: 'ndjson',
TILEJSON: 'tilejson',
JSON: 'json'
} as const;
Expand Down
9 changes: 5 additions & 4 deletions modules/carto/src/api/maps-v3-client.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable camelcase */
/**
* Maps API Client for Carto 3
*/
Expand Down Expand Up @@ -112,9 +113,9 @@ async function requestData({
}: RequestParams & {
format: Format;
}): Promise<Response | unknown> {
if (format === FORMATS.NDJSON) {
return request({method, url, accessToken, body, errorContext});
}
// if (format === FORMATS.NDJSON) {
// return request({method, url, accessToken, body, errorContext});
// }

const data = await requestJson<any>({method, url, accessToken, body, errorContext});
return data.rows ? data.rows : data;
Expand Down Expand Up @@ -395,7 +396,7 @@ async function _fetchDataUrl({
assert(url, `Format ${format} not available`);
} else {
// guess map format
const prioritizedFormats = [FORMATS.GEOJSON, FORMATS.JSON, FORMATS.NDJSON, FORMATS.TILEJSON];
const prioritizedFormats = [FORMATS.GEOJSON, FORMATS.JSON, FORMATS.TILEJSON];
for (const f of prioritizedFormats) {
url = getUrlFromMetadata(metadata, f);
if (url) {
Expand Down
39 changes: 34 additions & 5 deletions modules/carto/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
export {getDefaultCredentials, setDefaultCredentials} from './config';
export {default as CartoLayer} from './layers/carto-layer';
export {default as _CartoTileLayer} from './layers/carto-tile-layer';
export {default as _H3TileLayer} from './layers/h3-tile-layer';
export {default as CartoLayer} from './layers/carto-layer'; // <-- REMOVE in v9
export {default as VectorTileLayer} from './layers/vector-tile-layer';
export {default as H3TileLayer} from './layers/h3-tile-layer';
export {default as _PointLabelLayer} from './layers/point-label-layer';
export {default as _QuadbinTileLayer} from './layers/quadbin-tile-layer';
export {default as _RasterTileLayer} from './layers/raster-tile-layer';
export {default as QuadbinTileLayer} from './layers/quadbin-tile-layer';
export {default as RasterTileLayer} from './layers/raster-tile-layer';
export {default as BASEMAP} from './basemap';
export {default as colorBins} from './style/color-bins-style';
export {default as colorCategories} from './style/color-categories-style';
Expand All @@ -22,3 +22,32 @@ export {
} from './api';
export type {APIErrorContext, QueryParameters} from './api';
export type {CartoLayerProps} from './layers/carto-layer';

export {
cartoH3QuerySource,
cartoH3TableSource,
cartoH3TilesetSource,
cartoRasterSource,
cartoQuadbinQuerySource,
cartoQuadbinTableSource,
cartoQuadbinTilesetSource,
cartoVectorQuerySource,
cartoVectorTableSource,
cartoVectorTilesetSource,
SOURCE_DEFAULTS
} from './sources';
export type {
CartoTilejsonResult,
CartoH3QuerySourceOptions,
CartoH3TableSourceOptions,
CartoH3TilesetSourceOptions,
CartoRasterSourceOptions,
CartoQuadbinQuerySourceOptions,
CartoQuadbinTableSourceOptions,
CartoQuadbinTilesetSourceOptions,
CartoVectorQuerySourceOptions,
CartoVectorTableSourceOptions,
CartoVectorTilesetSourceOptions,
GeojsonResult,
JsonResult
} from './sources';
56 changes: 22 additions & 34 deletions modules/carto/src/layers/h3-tile-layer.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
import {
CompositeLayer,
CompositeLayerProps,
Layer,
LayersList,
UpdateParameters,
DefaultProps
} from '@deck.gl/core';
import {CompositeLayer, CompositeLayerProps, Layer, LayersList, DefaultProps} from '@deck.gl/core';
import {H3HexagonLayer} from '@deck.gl/geo-layers';
import H3Tileset2D, {getHexagonResolution} from './h3-tileset-2d';
import SpatialIndexTileLayer from './spatial-index-tile-layer';
import {TilejsonPropType, CartoTilejsonResult} from '../sources/common';
import {injectAccessToken} from './utils';

const renderSubLayers = props => {
const renderSubLayers = (props: H3HexagonLayerProps) => {
const {data} = props;
const {index} = props.tile;
if (!data || !data.length) return null;
Expand All @@ -23,7 +18,8 @@ const renderSubLayers = props => {
};

const defaultProps: DefaultProps<H3HexagonLayerProps> = {
aggregationResLevel: 4
aggregationResLevel: 4,
data: TilejsonPropType
};

/** All properties supported by H3TileLayer. */
Expand All @@ -34,8 +30,8 @@ export type H3TileLayerProps<DataT = any> = _H3TileLayerProps<DataT> & Composite
type H3HexagonLayerProps<DataT = any> = Record<string, any>;

/** Properties added by H3TileLayer. */
type _H3TileLayerProps<DataT> = H3HexagonLayerProps<DataT> & {
data: string;
type _H3TileLayerProps<DataT> = Omit<H3HexagonLayerProps<DataT>, 'data'> & {
data: null | CartoTilejsonResult | Promise<CartoTilejsonResult>;
aggregationResLevel?: number;
};

Expand All @@ -45,30 +41,24 @@ export default class H3TileLayer<DataT = any, ExtraPropsT extends {} = {}> exten
static layerName = 'H3TileLayer';
static defaultProps = defaultProps;

state!: {
tileJSON: any;
data: any;
};

initializeState(): void {
H3HexagonLayer._checkH3Lib();
this.setState({data: null, tileJSON: null});
}

updateState({changeFlags}: UpdateParameters<this>): void {
if (changeFlags.dataChanged) {
let {data} = this.props;
const tileJSON = data;
data = (tileJSON as any).tiles;
this.setState({data, tileJSON});
}
getLoadOptions(): any {
const loadOptions = super.getLoadOptions() || {};
const tileJSON = this.props.data as CartoTilejsonResult;
injectAccessToken(loadOptions, tileJSON.accessToken);
loadOptions.cartoSpatialTile = {...loadOptions.cartoSpatialTile, scheme: 'h3'};
return loadOptions;
}

renderLayers(): Layer | null | LayersList {
const {data, tileJSON} = this.state;
let minresolution = parseInt(tileJSON.minresolution);
let maxresolution = parseInt(tileJSON.maxresolution);
const tileJSON = this.props.data as CartoTilejsonResult;
if (!tileJSON) return null;

const {tiles: data} = tileJSON;
let {minresolution, maxresolution} = tileJSON;
// Convert Mercator zooms provided in props into H3 res levels
// and clip into valid range provided from the tilejson
if (this.props.minZoom) {
Expand All @@ -87,19 +77,17 @@ export default class H3TileLayer<DataT = any, ExtraPropsT extends {} = {}> exten
// The naming is unfortunate, but minZoom & maxZoom in the context
// of a Tileset2D refer to the resolution levels, not the Mercator zooms
return [
// @ts-ignore
new SpatialIndexTileLayer(this.props, {
id: `h3-tile-layer-${this.props.id}`,
data,
// @ts-expect-error Tileset2D should be generic over TileIndex
TilesetClass: H3Tileset2D,
// TODO: Tileset2D should be generic over TileIndex type
TilesetClass: H3Tileset2D as any,
renderSubLayers,
// minZoom and maxZoom are H3 resolutions, however we must use this naming as that is what the Tileset2D class expects
minZoom: minresolution,
maxZoom: maxresolution,
loadOptions: {
...this.getLoadOptions(),
cartoSpatialTile: {scheme: 'h3'}
}
loadOptions: this.getLoadOptions()
})
];
}
Expand Down
51 changes: 19 additions & 32 deletions modules/carto/src/layers/quadbin-tile-layer.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
import {
CompositeLayer,
CompositeLayerProps,
Layer,
LayersList,
UpdateParameters,
DefaultProps
} from '@deck.gl/core';
import {CompositeLayer, CompositeLayerProps, Layer, LayersList, DefaultProps} from '@deck.gl/core';
import QuadbinLayer, {QuadbinLayerProps} from './quadbin-layer';
import QuadbinTileset2D from './quadbin-tileset-2d';
import SpatialIndexTileLayer from './spatial-index-tile-layer';
import {hexToBigInt} from 'quadbin';
import {TilejsonPropType, CartoTilejsonResult} from '../sources/common';
import {injectAccessToken} from './utils';

export const renderSubLayers = props => {
const {data} = props;
Expand All @@ -21,16 +16,17 @@ export const renderSubLayers = props => {
};

const defaultProps: DefaultProps<QuadbinTileLayerProps> = {
aggregationResLevel: 6
aggregationResLevel: 6,
data: TilejsonPropType
};

/** All properties supported by QuadbinTileLayer. */
export type QuadbinTileLayerProps<DataT = any> = _QuadbinTileLayerProps<DataT> &
CompositeLayerProps;

/** Properties added by QuadbinTileLayer. */
type _QuadbinTileLayerProps<DataT> = QuadbinLayerProps<DataT> & {
data: string;
type _QuadbinTileLayerProps<DataT> = Omit<QuadbinLayerProps<DataT>, 'data'> & {
data: null | CartoTilejsonResult | Promise<CartoTilejsonResult>;
aggregationResLevel?: number;
};

Expand All @@ -41,38 +37,29 @@ export default class QuadbinTileLayer<
static layerName = 'QuadbinTileLayer';
static defaultProps = defaultProps;

state!: {
tileJSON: any;
data: any;
};
initializeState(): void {
this.setState({data: null, tileJSON: null});
}

updateState({changeFlags}: UpdateParameters<this>): void {
if (changeFlags.dataChanged) {
let {data} = this.props;
const tileJSON = data;
data = (tileJSON as any).tiles;
this.setState({data, tileJSON});
}
getLoadOptions(): any {
const loadOptions = super.getLoadOptions() || {};
const tileJSON = this.props.data as CartoTilejsonResult;
injectAccessToken(loadOptions, tileJSON.accessToken);
loadOptions.cartoSpatialTile = {...loadOptions.cartoSpatialTile, scheme: 'quadbin'};
return loadOptions;
}

renderLayers(): Layer | null | LayersList {
const {data, tileJSON} = this.state;
const maxZoom = parseInt(tileJSON?.maxresolution);
const tileJSON = this.props.data as CartoTilejsonResult;
if (!tileJSON) return null;

const {tiles: data, maxresolution: maxZoom} = tileJSON;
return [
// @ts-ignore
new SpatialIndexTileLayer(this.props, {
id: `quadbin-tile-layer-${this.props.id}`,
data,
// TODO: Tileset2D should be generic over TileIndex type
TilesetClass: QuadbinTileset2D as any,
renderSubLayers,
maxZoom,
loadOptions: {
...this.getLoadOptions(),
cartoSpatialTile: {scheme: 'quadbin'}
}
loadOptions: this.getLoadOptions()
})
];
}
Expand Down
Loading

0 comments on commit a2b5690

Please sign in to comment.