@deck.gl/carto 8.8.0-alpha.3 → 8.8.0-alpha.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/dist/dist.dev.js +383 -247
  2. package/dist/es5/api/layer-map.js +7 -5
  3. package/dist/es5/api/layer-map.js.map +1 -1
  4. package/dist/es5/layers/carto-layer.js +3 -1
  5. package/dist/es5/layers/carto-layer.js.map +1 -1
  6. package/dist/es5/layers/carto-tile-layer.js +17 -12
  7. package/dist/es5/layers/carto-tile-layer.js.map +1 -1
  8. package/dist/es5/layers/h3-tile-layer.js +34 -13
  9. package/dist/es5/layers/h3-tile-layer.js.map +1 -1
  10. package/dist/es5/layers/h3-tileset-2d.js +21 -11
  11. package/dist/es5/layers/h3-tileset-2d.js.map +1 -1
  12. package/dist/es5/layers/quadkey-tile-layer.js +31 -14
  13. package/dist/es5/layers/quadkey-tile-layer.js.map +1 -1
  14. package/dist/es5/layers/quadkey-tileset-2d.js.map +1 -1
  15. package/dist/es5/layers/schema/carto-tile.js +261 -188
  16. package/dist/es5/layers/schema/carto-tile.js.map +1 -1
  17. package/dist/es5/layers/spatial-index-tile-layer.js +92 -0
  18. package/dist/es5/layers/spatial-index-tile-layer.js.map +1 -0
  19. package/dist/esm/api/layer-map.js +8 -6
  20. package/dist/esm/api/layer-map.js.map +1 -1
  21. package/dist/esm/layers/carto-layer.js +3 -1
  22. package/dist/esm/layers/carto-layer.js.map +1 -1
  23. package/dist/esm/layers/carto-tile-layer.js +20 -16
  24. package/dist/esm/layers/carto-tile-layer.js.map +1 -1
  25. package/dist/esm/layers/h3-tile-layer.js +24 -10
  26. package/dist/esm/layers/h3-tile-layer.js.map +1 -1
  27. package/dist/esm/layers/h3-tileset-2d.js +27 -12
  28. package/dist/esm/layers/h3-tileset-2d.js.map +1 -1
  29. package/dist/esm/layers/quadkey-tile-layer.js +22 -13
  30. package/dist/esm/layers/quadkey-tile-layer.js.map +1 -1
  31. package/dist/esm/layers/quadkey-tileset-2d.js.map +1 -1
  32. package/dist/esm/layers/schema/carto-tile.js +174 -189
  33. package/dist/esm/layers/schema/carto-tile.js.map +1 -1
  34. package/dist/esm/layers/spatial-index-tile-layer.js +57 -0
  35. package/dist/esm/layers/spatial-index-tile-layer.js.map +1 -0
  36. package/dist.min.js +4 -4
  37. package/package.json +7 -4
  38. package/src/api/layer-map.ts +16 -7
  39. package/src/layers/carto-layer.ts +18 -5
  40. package/src/layers/{carto-tile-layer.js → carto-tile-layer.ts} +63 -26
  41. package/src/layers/h3-tile-layer.ts +78 -0
  42. package/src/layers/h3-tileset-2d.ts +118 -0
  43. package/src/layers/quadkey-tile-layer.ts +68 -0
  44. package/src/layers/{quadkey-tileset-2d.js → quadkey-tileset-2d.ts} +10 -5
  45. package/src/layers/schema/carto-tile.ts +221 -0
  46. package/src/layers/spatial-index-tile-layer.ts +49 -0
  47. package/typed/api/index.d.ts +4 -0
  48. package/typed/api/index.d.ts.map +1 -0
  49. package/typed/api/layer-map.d.ts +54 -0
  50. package/typed/api/layer-map.d.ts.map +1 -0
  51. package/typed/api/maps-api-common.d.ts +65 -0
  52. package/typed/api/maps-api-common.d.ts.map +1 -0
  53. package/typed/api/maps-client.d.ts +18 -0
  54. package/typed/api/maps-client.d.ts.map +1 -0
  55. package/typed/api/maps-v3-client.d.ts +45 -0
  56. package/typed/api/maps-v3-client.d.ts.map +1 -0
  57. package/typed/api/parseMap.d.ts +11 -0
  58. package/typed/api/parseMap.d.ts.map +1 -0
  59. package/typed/basemap.d.ts +10 -0
  60. package/typed/basemap.d.ts.map +1 -0
  61. package/typed/config.d.ts +26 -0
  62. package/typed/config.d.ts.map +1 -0
  63. package/typed/index.d.ts +12 -0
  64. package/typed/index.d.ts.map +1 -0
  65. package/typed/layers/carto-layer.d.ts +98 -0
  66. package/typed/layers/carto-layer.d.ts.map +1 -0
  67. package/typed/layers/carto-tile-layer.d.ts +63 -0
  68. package/typed/layers/carto-tile-layer.d.ts.map +1 -0
  69. package/typed/layers/h3-tile-layer.d.ts +23 -0
  70. package/typed/layers/h3-tile-layer.d.ts.map +1 -0
  71. package/typed/layers/h3-tileset-2d.d.ts +18 -0
  72. package/typed/layers/h3-tileset-2d.d.ts.map +1 -0
  73. package/typed/layers/quadkey-tile-layer.d.ts +23 -0
  74. package/typed/layers/quadkey-tile-layer.d.ts.map +1 -0
  75. package/typed/layers/quadkey-tileset-2d.d.ts +15 -0
  76. package/typed/layers/quadkey-tileset-2d.d.ts.map +1 -0
  77. package/typed/layers/schema/carto-tile.d.ts +44 -0
  78. package/typed/layers/schema/carto-tile.d.ts.map +1 -0
  79. package/typed/layers/spatial-index-tile-layer.d.ts +11 -0
  80. package/typed/layers/spatial-index-tile-layer.d.ts.map +1 -0
  81. package/typed/package.json +6 -0
  82. package/typed/style/color-bins-style.d.ts +9 -0
  83. package/typed/style/color-bins-style.d.ts.map +1 -0
  84. package/typed/style/color-categories-style.d.ts +10 -0
  85. package/typed/style/color-categories-style.d.ts.map +1 -0
  86. package/typed/style/color-continuous-style.d.ts +9 -0
  87. package/typed/style/color-continuous-style.d.ts.map +1 -0
  88. package/typed/style/palette.d.ts +7 -0
  89. package/typed/style/palette.d.ts.map +1 -0
  90. package/typed/style/utils.d.ts +8 -0
  91. package/typed/style/utils.d.ts.map +1 -0
  92. package/typed/utils.d.ts +2 -0
  93. package/typed/utils.d.ts.map +1 -0
  94. package/src/layers/h3-tile-layer.js +0 -44
  95. package/src/layers/h3-tileset-2d.js +0 -82
  96. package/src/layers/quadkey-tile-layer.js +0 -42
  97. package/src/layers/schema/carto-tile.js +0 -195
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@deck.gl/carto",
3
3
  "description": "CARTO official integration with Deck.gl. Build geospatial applications using CARTO and Deck.gl.",
4
4
  "license": "MIT",
5
- "version": "8.8.0-alpha.3",
5
+ "version": "8.8.0-alpha.6",
6
6
  "publishConfig": {
7
7
  "access": "public"
8
8
  },
@@ -23,6 +23,7 @@
23
23
  "files": [
24
24
  "dist",
25
25
  "src",
26
+ "typed",
26
27
  "dist.min.js"
27
28
  ],
28
29
  "sideEffects": false,
@@ -35,17 +36,19 @@
35
36
  "@loaders.gl/loader-utils": "^3.2.0-alpha.4",
36
37
  "@loaders.gl/mvt": "^3.2.0-alpha.4",
37
38
  "@loaders.gl/tiles": "^3.2.0-alpha.4",
38
- "@luma.gl/constants": "^8.5.10",
39
- "@math.gl/web-mercator": "3.6.0-alpha.5",
39
+ "@luma.gl/constants": "^8.5.13",
40
+ "@math.gl/web-mercator": "3.6.0-alpha.8",
40
41
  "cartocolor": "^4.0.2",
41
42
  "d3-array": "^2.8.0",
42
43
  "d3-color": "^2.0.0",
43
44
  "d3-format": "^2.0.0",
44
45
  "d3-scale": "^3.2.3",
46
+ "h3-js": "^3.6.0",
45
47
  "moment-timezone": "^0.5.33",
46
48
  "pbf": "^3.2.1"
47
49
  },
48
50
  "devDependencies": {
51
+ "@loaders.gl/schema": "^3.2.0-alpha.4",
49
52
  "@types/d3-array": "^3.0.2",
50
53
  "@types/d3-color": "^1.4.2",
51
54
  "@types/d3-scale": "^3.0.0"
@@ -58,5 +61,5 @@
58
61
  "@deck.gl/layers": "^8.0.0",
59
62
  "@loaders.gl/core": "^3.0.0"
60
63
  },
61
- "gitHead": "edad7cf75b75a137d63ec89d2d644727d3082e25"
64
+ "gitHead": "6885ccab01c91a7632385f566c9377f8ae387e7c"
62
65
  }
@@ -13,6 +13,7 @@ import {
13
13
  import {format as d3Format} from 'd3-format';
14
14
  import moment from 'moment-timezone';
15
15
 
16
+ import {Layer, _ConstructorOf as ConstructorOf} from '@deck.gl/core';
16
17
  import {CPUGridLayer, HeatmapLayer, HexagonLayer} from '@deck.gl/aggregation-layers';
17
18
  import {GeoJsonLayer} from '@deck.gl/layers';
18
19
  import {H3HexagonLayer, MVTLayer} from '@deck.gl/geo-layers';
@@ -101,7 +102,7 @@ const defaultProps = {
101
102
  wrapLongitude: false
102
103
  };
103
104
 
104
- function mergePropMaps(a = {}, b = {}) {
105
+ function mergePropMaps(a: Record<string, any> = {}, b: Record<string, any> = {}) {
105
106
  return {...a, ...b, visConfig: {...a.visConfig, ...b.visConfig}};
106
107
  }
107
108
 
@@ -109,7 +110,7 @@ export function getLayer(
109
110
  type: string,
110
111
  config,
111
112
  dataset
112
- ): {Layer: any; propMap: any; defaultProps: any} {
113
+ ): {Layer: ConstructorOf<Layer>; propMap: any; defaultProps: any} {
113
114
  if (type === 'mvt' || type === 'tileset') {
114
115
  return getTileLayer(dataset);
115
116
  }
@@ -118,7 +119,11 @@ export function getLayer(
118
119
  const getPosition = d => d[geoColumn].coordinates;
119
120
 
120
121
  const hexagonId = config.columns?.hex_id;
121
- const layer = {
122
+
123
+ const layerTypeDefs: Record<
124
+ string,
125
+ {Layer: ConstructorOf<Layer>; propMap?: any; defaultProps?: any}
126
+ > = {
122
127
  point: {
123
128
  Layer: GeoJsonLayer,
124
129
  propMap: {visConfig: {outline: 'stroked'}}
@@ -146,12 +151,16 @@ export function getLayer(
146
151
  propMap: {visConfig: {coverage: 'coverage'}},
147
152
  defaultProps: {getHexagon: d => d[hexagonId], stroked: false}
148
153
  }
149
- }[type];
154
+ };
155
+
156
+ const layer = layerTypeDefs[type];
150
157
 
151
158
  assert(layer, `Unsupported layer type: ${type}`);
152
- layer.propMap = mergePropMaps(sharedPropMap, layer.propMap);
153
- layer.defaultProps = {...defaultProps, ...layer.defaultProps};
154
- return layer;
159
+ return {
160
+ ...layer,
161
+ propMap: mergePropMaps(sharedPropMap, layer.propMap),
162
+ defaultProps: {...defaultProps, ...layer.defaultProps}
163
+ };
155
164
  }
156
165
 
157
166
  function getTileLayer(dataset) {
@@ -57,10 +57,20 @@ const defaultProps = {
57
57
  geoColumn: null,
58
58
 
59
59
  // (Array<String>, optional): names of columns to fetch. By default, all columns are fetched.
60
- columns: {type: 'array', value: null}
60
+ columns: {type: 'array', value: null},
61
+
62
+ // (String, optional): aggregration SQL expression. Only used for spatial index datasets
63
+ aggregationExp: null,
64
+
65
+ // (Number, optional): aggregration resolution level. Only used for spatial index datasets, defaults to 6 for quadkeys, 4 for h3
66
+ aggregationResLevel: null
61
67
  };
62
68
 
63
- export interface CartoLayerProps<DataT = any> extends CompositeLayerProps<DataT> {
69
+ /** All properties supported by CartoLayer. */
70
+ export type CartoLayerProps<DataT = any> = _CartoLayerProps & CompositeLayerProps<DataT>;
71
+
72
+ /** Properties added by CartoLayer. */
73
+ type _CartoLayerProps = {
64
74
  /**
65
75
  * Either a SQL query or a name of dataset/tileset.
66
76
  */
@@ -141,9 +151,11 @@ export interface CartoLayerProps<DataT = any> extends CompositeLayerProps<DataT>
141
151
  onDataError?: (err: unknown) => void;
142
152
 
143
153
  clientId?: string;
144
- }
154
+ };
145
155
 
146
- export default class CartoLayer<DataT = any> extends CompositeLayer<CartoLayerProps<DataT>> {
156
+ export default class CartoLayer<ExtraProps = {}> extends CompositeLayer<
157
+ Required<_CartoLayerProps> & ExtraProps
158
+ > {
147
159
  static layerName = 'CartoLayer';
148
160
  static defaultProps = defaultProps as any;
149
161
 
@@ -231,7 +243,7 @@ export default class CartoLayer<DataT = any> extends CompositeLayer<CartoLayerPr
231
243
  const localConfig = {...getDefaultCredentials(), ...credentials};
232
244
  const {apiVersion} = localConfig;
233
245
 
234
- let result: FetchLayerDataResult;
246
+ let result: Partial<FetchLayerDataResult>;
235
247
  if (apiVersion === API_VERSIONS.V1 || apiVersion === API_VERSIONS.V2) {
236
248
  result = {
237
249
  data: await getDataV2({type, source, credentials: credentials as ClassicCredentials})
@@ -270,6 +282,7 @@ export default class CartoLayer<DataT = any> extends CompositeLayer<CartoLayerPr
270
282
  const {uniqueIdProperty} = defaultProps;
271
283
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
272
284
  const {data: _notUsed, ...propsNoData} = this.props;
285
+ // @ts-expect-error 'uniqueIdProperty' is specified more than once, so this usage will be overwritten.
273
286
  const props = {uniqueIdProperty, ...propsNoData};
274
287
 
275
288
  if (apiVersion === API_VERSIONS.V1 || apiVersion === API_VERSIONS.V2) {
@@ -2,28 +2,38 @@
2
2
  import Protobuf from 'pbf';
3
3
  import {log} from '@deck.gl/core';
4
4
  import {ClipExtension} from '@deck.gl/extensions';
5
- import {MVTLayer, _getURLFromTemplate} from '@deck.gl/geo-layers';
5
+ import {
6
+ MVTLayer,
7
+ MVTLayerProps,
8
+ TileLayer,
9
+ _getURLFromTemplate,
10
+ _Tile2DHeader,
11
+ _TileLoadProps as TileLoadProps
12
+ } from '@deck.gl/geo-layers';
6
13
  import {GeoJsonLayer} from '@deck.gl/layers';
7
14
  import {geojsonToBinary} from '@loaders.gl/gis';
8
- import {Tile} from './schema/carto-tile';
9
- import {TILE_FORMATS} from '../api/maps-api-common';
15
+ import {Properties, Tile, TileReader} from './schema/carto-tile';
16
+ import {TileFormat, TILE_FORMATS} from '../api/maps-api-common';
17
+ import {LoaderOptions, LoaderWithParser} from '@loaders.gl/loader-utils';
18
+ import type {BinaryFeatures} from '@loaders.gl/schema';
19
+ import type {Feature} from 'geojson';
10
20
 
11
- function parseJSON(arrayBuffer) {
21
+ function parseJSON(arrayBuffer: ArrayBuffer): any {
12
22
  return JSON.parse(new TextDecoder().decode(arrayBuffer));
13
23
  }
14
24
 
15
- function parsePbf(buffer) {
25
+ function parsePbf(buffer: ArrayBuffer): Tile {
16
26
  const pbf = new Protobuf(buffer);
17
- const tile = Tile.read(pbf);
27
+ const tile = TileReader.read(pbf);
18
28
  return tile;
19
29
  }
20
30
 
21
- function unpackProperties(properties) {
31
+ function unpackProperties(properties: Properties[]) {
22
32
  if (!properties || !properties.length) {
23
33
  return [];
24
34
  }
25
35
  return properties.map(item => {
26
- const currentRecord = {};
36
+ const currentRecord: Record<string, unknown> = {};
27
37
  item.data.forEach(({key, value}) => {
28
38
  currentRecord[key] = value;
29
39
  });
@@ -31,7 +41,7 @@ function unpackProperties(properties) {
31
41
  });
32
42
  }
33
43
 
34
- function parseCartoTile(arrayBuffer, options) {
44
+ function parseCartoTile(arrayBuffer: ArrayBuffer, options?: LoaderOptions): BinaryFeatures | null {
35
45
  if (!arrayBuffer) return null;
36
46
  const formatTiles = options && options.cartoTile && options.cartoTile.formatTiles;
37
47
  if (formatTiles === TILE_FORMATS.GEOJSON) return geojsonToBinary(parseJSON(arrayBuffer).features);
@@ -45,13 +55,15 @@ function parseCartoTile(arrayBuffer, options) {
45
55
  polygons: {...polygons, properties: unpackProperties(polygons.properties)}
46
56
  };
47
57
 
48
- return data;
58
+ // Note: there is slight, difference in `numericProps` type, however geojson/mvtlayer can cope with this
59
+ return data as unknown as BinaryFeatures;
49
60
  }
50
61
 
51
62
  const defaultTileFormat = TILE_FORMATS.BINARY;
52
63
 
53
- const CartoTileLoader = {
64
+ const CartoTileLoader: LoaderWithParser = {
54
65
  name: 'CARTO Tile',
66
+ version: '1',
55
67
  id: 'cartoTile',
56
68
  module: 'carto',
57
69
  extensions: ['pbf'],
@@ -73,8 +85,29 @@ const defaultProps = {
73
85
  loaders: [CartoTileLoader]
74
86
  };
75
87
 
76
- export default class CartoTileLayer extends MVTLayer {
77
- getTileData(tile) {
88
+ /** All properties supported by CartoTileLayer. */
89
+ export type CartoTileLayerProps<DataT extends Feature = Feature> = _CartoTileLayerProps &
90
+ MVTLayerProps<DataT>;
91
+
92
+ /** Properties added by CartoTileLayer. */
93
+ type _CartoTileLayerProps = {
94
+ /** Use to override the default tile data format.
95
+ *
96
+ * Possible values are: `TILE_FORMATS.BINARY`, `TILE_FORMATS.GEOJSON` and `TILE_FORMATS.MVT`.
97
+ *
98
+ * Only supported when `apiVersion` is `API_VERSIONS.V3` and `format` is `FORMATS.TILEJSON`.
99
+ */
100
+ formatTiles?: TileFormat;
101
+ };
102
+
103
+ export default class CartoTileLayer<
104
+ DataT extends Feature = Feature,
105
+ ExtraProps = {}
106
+ > extends MVTLayer<DataT, Required<_CartoTileLayerProps> & ExtraProps> {
107
+ static layerName = 'CartoTileLayer';
108
+ static defaultProps = defaultProps;
109
+
110
+ getTileData(tile: TileLoadProps) {
78
111
  const url = _getURLFromTemplate(this.state.data, tile);
79
112
  if (!url) {
80
113
  return Promise.reject('Invalid URL');
@@ -100,25 +133,29 @@ export default class CartoTileLayer extends MVTLayer {
100
133
  return fetch(url, {propName: 'data', layer: this, loadOptions, signal});
101
134
  }
102
135
 
103
- renderSubLayers(props) {
136
+ renderSubLayers(
137
+ props: TileLayer['props'] & {
138
+ id: string;
139
+ data: any;
140
+ _offset: number;
141
+ tile: _Tile2DHeader;
142
+ }
143
+ ): GeoJsonLayer | null {
104
144
  if (props.data === null) {
105
145
  return null;
106
146
  }
107
147
 
108
- props.autoHighlight = false;
148
+ const tileBbox = props.tile.bbox as any;
149
+ const {west, south, east, north} = tileBbox;
109
150
 
110
- const {
111
- bbox: {west, south, east, north}
112
- } = props.tile;
113
- props.extensions = [new ClipExtension(), ...(props.extensions || [])];
114
- props.clipBounds = [west, south, east, north];
151
+ const subLayerProps = {
152
+ ...props,
153
+ autoHighlight: false,
154
+ extensions: [new ClipExtension(), ...(props.extensions || [])],
155
+ clipBounds: [west, south, east, north]
156
+ };
115
157
 
116
- const subLayer = new GeoJsonLayer({
117
- ...props
118
- });
158
+ const subLayer = new GeoJsonLayer(subLayerProps);
119
159
  return subLayer;
120
160
  }
121
161
  }
122
-
123
- CartoTileLayer.layerName = 'CartoTileLayer';
124
- CartoTileLayer.defaultProps = defaultProps;
@@ -0,0 +1,78 @@
1
+ import {
2
+ CompositeLayer,
3
+ CompositeLayerProps,
4
+ Layer,
5
+ LayersList,
6
+ UpdateParameters
7
+ } from '@deck.gl/core';
8
+ import {H3HexagonLayer} from '@deck.gl/geo-layers';
9
+ import H3Tileset2D from './h3-tileset-2d';
10
+ import SpatialIndexTileLayer from './spatial-index-tile-layer';
11
+
12
+ const renderSubLayers = props => {
13
+ const {data} = props;
14
+ const {index} = props.tile;
15
+ if (!data || !data.length) return null;
16
+
17
+ return new H3HexagonLayer(props, {
18
+ getHexagon: d => d.id,
19
+ centerHexagon: index,
20
+ highPrecision: true
21
+ });
22
+ };
23
+
24
+ const defaultProps = {
25
+ aggregationResLevel: 4
26
+ };
27
+
28
+ /** All properties supported by H3TileLayer. */
29
+ export type H3TileLayerProps<DataT = any> = _H3TileLayerProps<DataT> & CompositeLayerProps<DataT>;
30
+
31
+ // TODO: use type from h3-hexagon-layer when available
32
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
33
+ type H3HexagonLayerProps<DataT = any> = Record<string, any>;
34
+
35
+ /** Properties added by H3TileLayer. */
36
+ type _H3TileLayerProps<DataT = any> = H3HexagonLayerProps<DataT> & {
37
+ aggregationResLevel?: number;
38
+ };
39
+
40
+ export default class H3TileLayer<DataT = any, ExtraPropsT = {}> extends CompositeLayer<
41
+ ExtraPropsT & Required<_H3TileLayerProps<DataT>>
42
+ > {
43
+ static layerName = 'H3TileLayer';
44
+ static defaultProps = defaultProps;
45
+
46
+ state!: {
47
+ tileJSON: any;
48
+ data: any;
49
+ };
50
+
51
+ initializeState(): void {
52
+ this.setState({data: null, tileJSON: null});
53
+ }
54
+
55
+ updateState({changeFlags}: UpdateParameters<this>): void {
56
+ if (changeFlags.dataChanged) {
57
+ let {data} = this.props;
58
+ const tileJSON = data;
59
+ data = (tileJSON as any).tiles;
60
+ this.setState({data, tileJSON});
61
+ }
62
+ }
63
+
64
+ renderLayers(): Layer | null | LayersList {
65
+ const {data, tileJSON} = this.state;
66
+ const maxZoom = parseInt(tileJSON.maxresolution);
67
+ return [
68
+ new SpatialIndexTileLayer(this.props, {
69
+ id: `h3-tile-layer-${this.props.id}`,
70
+ data,
71
+ // @ts-expect-error Tileset2D should be generic over TileIndex
72
+ TilesetClass: H3Tileset2D,
73
+ renderSubLayers,
74
+ maxZoom
75
+ })
76
+ ];
77
+ }
78
+ }
@@ -0,0 +1,118 @@
1
+ import {_Tileset2D as Tileset2D, GeoBoundingBox} from '@deck.gl/geo-layers';
2
+ import {
3
+ polyfill,
4
+ getRes0Indexes,
5
+ geoToH3,
6
+ h3GetResolution,
7
+ h3ToGeoBoundary,
8
+ h3ToParent,
9
+ kRing
10
+ } from 'h3-js';
11
+
12
+ export type H3TileIndex = {i: string};
13
+
14
+ function getHexagonsInBoundingBox(
15
+ {west, north, east, south}: GeoBoundingBox,
16
+ resolution: number
17
+ ): string[] {
18
+ if (resolution === 0) {
19
+ return getRes0Indexes();
20
+ }
21
+ if (east - west > 180) {
22
+ // This is a known issue in h3-js: polyfill does not work correctly
23
+ // when longitude span is larger than 180 degrees.
24
+ return getHexagonsInBoundingBox({west, north, east: 0, south}, resolution).concat(
25
+ getHexagonsInBoundingBox({west: 0, north, east, south}, resolution)
26
+ );
27
+ }
28
+
29
+ // `polyfill()` fills based on hexagon center, which means tiles vanish
30
+ // prematurely. Get more accurate coverage by oversampling
31
+ const oversample = 2;
32
+ const h3Indices = polyfill(
33
+ [
34
+ [
35
+ [west, north],
36
+ [west, south],
37
+ [east, south],
38
+ [east, north],
39
+ [west, north]
40
+ ]
41
+ ],
42
+ resolution + oversample,
43
+ true
44
+ );
45
+
46
+ return oversample ? [...new Set(h3Indices.map(i => h3ToParent(i, resolution)))] : h3Indices;
47
+ }
48
+
49
+ function tileToBoundingBox(index: string): GeoBoundingBox {
50
+ const coordinates = h3ToGeoBoundary(index);
51
+ const latitudes = coordinates.map(c => c[0]);
52
+ const longitudes = coordinates.map(c => c[1]);
53
+ const west = Math.min(...longitudes);
54
+ const south = Math.min(...latitudes);
55
+ const east = Math.max(...longitudes);
56
+ const north = Math.max(...latitudes);
57
+ return {west, south, east, north};
58
+ }
59
+
60
+ // Resolution conversion function. Takes a WebMercatorViewport and returns
61
+ // a H3 resolution such that the screen space size of the hexagons is
62
+ // similar
63
+ // Relative scale factor (0 = no biasing, 2 = a few hexagons cover view)
64
+ const BIAS = 2;
65
+ function getHexagonResolution(viewport): number {
66
+ const hexagonScaleFactor = (2 / 3) * viewport.zoom;
67
+ const latitudeScaleFactor = Math.log(1 / Math.cos((Math.PI * viewport.latitude) / 180));
68
+
69
+ // Clip and bias
70
+ return Math.max(0, Math.floor(hexagonScaleFactor + latitudeScaleFactor - BIAS));
71
+ }
72
+
73
+ export default class H3Tileset2D extends Tileset2D {
74
+ // @ts-expect-error Tileset2D should be generic over TileIndex
75
+ getTileIndices({viewport, minZoom, maxZoom}): H3TileIndex[] {
76
+ const [east, south, west, north] = viewport.getBounds();
77
+
78
+ let z = getHexagonResolution(viewport);
79
+ let indices: string[];
80
+ if (typeof minZoom === 'number' && Number.isFinite(minZoom) && z < minZoom) {
81
+ z = minZoom;
82
+ }
83
+ if (typeof maxZoom === 'number' && Number.isFinite(maxZoom) && z > maxZoom) {
84
+ z = maxZoom;
85
+
86
+ // Once we are at max zoom, getHexagonsInBoundingBox doesn't work, simply
87
+ // get a ring centered on the hexagon in the viewport center
88
+ const center = geoToH3(viewport.latitude, viewport.longitude, maxZoom);
89
+ indices = kRing(center, 1);
90
+ } else {
91
+ indices = getHexagonsInBoundingBox({west, north, east, south}, z);
92
+ }
93
+
94
+ return indices.map(i => ({i}));
95
+ }
96
+
97
+ // @ts-expect-error Tileset2D should be generic over TileIndex
98
+ getTileId({i}: H3TileIndex): string {
99
+ return i;
100
+ }
101
+
102
+ // @ts-expect-error Tileset2D should be generic over TileIndex
103
+ getTileMetadata({i}: H3TileIndex) {
104
+ return {bbox: tileToBoundingBox(i)};
105
+ }
106
+
107
+ // @ts-expect-error Tileset2D should be generic over TileIndex
108
+ getTileZoom({i}: H3TileIndex): number {
109
+ return h3GetResolution(i);
110
+ }
111
+
112
+ // @ts-expect-error Tileset2D should be generic over TileIndex
113
+ getParentIndex(index: H3TileIndex): H3TileIndex {
114
+ const resolution = h3GetResolution(index.i);
115
+ const i = h3ToParent(index.i, resolution - 1);
116
+ return {i};
117
+ }
118
+ }
@@ -0,0 +1,68 @@
1
+ import {
2
+ CompositeLayer,
3
+ CompositeLayerProps,
4
+ Layer,
5
+ LayersList,
6
+ UpdateParameters
7
+ } from '@deck.gl/core';
8
+ import {QuadkeyLayer, QuadkeyLayerProps} from '@deck.gl/geo-layers';
9
+ import QuadkeyTileset2D from './quadkey-tileset-2d';
10
+ import SpatialIndexTileLayer from './spatial-index-tile-layer';
11
+
12
+ const renderSubLayers = props => {
13
+ const {data} = props;
14
+ if (!data || !data.length) return null;
15
+ return new QuadkeyLayer(props, {getQuadkey: d => d.id});
16
+ };
17
+
18
+ const defaultProps = {
19
+ aggregationResLevel: 6
20
+ };
21
+
22
+ /** All properties supported by QuadkeyTileLayer. */
23
+ export type QuadkeyTileLayerProps<DataT = any> = _QuadkeyTileLayerProps<DataT> &
24
+ CompositeLayerProps<DataT>;
25
+
26
+ /** Properties added by QuadkeyTileLayer. */
27
+ type _QuadkeyTileLayerProps<DataT> = QuadkeyLayerProps<DataT> & {
28
+ aggregationResLevel?: number;
29
+ };
30
+
31
+ export default class QuadkeyTileLayer<DataT = any, ExtraProps = {}> extends CompositeLayer<
32
+ ExtraProps & Required<_QuadkeyTileLayerProps<DataT>>
33
+ > {
34
+ static layerName = 'QuadkeyTileLayer';
35
+ static defaultProps = defaultProps;
36
+
37
+ state!: {
38
+ tileJSON: any;
39
+ data: any;
40
+ };
41
+ initializeState(): void {
42
+ this.setState({data: null, tileJSON: null});
43
+ }
44
+
45
+ updateState({changeFlags}: UpdateParameters<this>): void {
46
+ if (changeFlags.dataChanged) {
47
+ let {data} = this.props;
48
+ const tileJSON = data;
49
+ data = (tileJSON as any).tiles;
50
+ this.setState({data, tileJSON});
51
+ }
52
+ }
53
+
54
+ renderLayers(): Layer | null | LayersList {
55
+ const {data, tileJSON} = this.state;
56
+ const maxZoom = parseInt(tileJSON?.maxresolution);
57
+ return [
58
+ new SpatialIndexTileLayer(this.props, {
59
+ id: `quadkey-tile-layer-${this.props.id}`,
60
+ data,
61
+ // TODO: Tileset2D should be generic over TileIndex type
62
+ TilesetClass: QuadkeyTileset2D as any,
63
+ renderSubLayers,
64
+ maxZoom
65
+ })
66
+ ];
67
+ }
68
+ }
@@ -1,6 +1,7 @@
1
1
  import {_Tileset2D as Tileset2D} from '@deck.gl/geo-layers';
2
2
 
3
- function tileToQuadkey(tile) {
3
+ type QuadkeyTileIndex = {i: string};
4
+ function tileToQuadkey(tile): QuadkeyTileIndex {
4
5
  let index = '';
5
6
  for (let z = tile.z; z > 0; z--) {
6
7
  let b = 0;
@@ -13,11 +14,13 @@ function tileToQuadkey(tile) {
13
14
  }
14
15
 
15
16
  export default class QuadkeyTileset2D extends Tileset2D {
16
- getTileIndices(opts) {
17
+ // @ts-expect-error for spatial indices, TileSet2d should be parametrized by TileIndexT
18
+ getTileIndices(opts): QuadkeyTileIndex[] {
17
19
  return super.getTileIndices(opts).map(tileToQuadkey);
18
20
  }
19
21
 
20
- getTileId({i}) {
22
+ // @ts-expect-error TileIndex must be generic
23
+ getTileId({i}: QuadkeyTileIndex) {
21
24
  return i;
22
25
  }
23
26
 
@@ -25,11 +28,13 @@ export default class QuadkeyTileset2D extends Tileset2D {
25
28
  return {};
26
29
  }
27
30
 
28
- getTileZoom({i}) {
31
+ // @ts-expect-error TileIndex must be generic
32
+ getTileZoom({i}: QuadkeyTileIndex) {
29
33
  return i.length;
30
34
  }
31
35
 
32
- getParentIndex(index) {
36
+ // @ts-expect-error TileIndex must be generic
37
+ getParentIndex(index: QuadkeyTileIndex) {
33
38
  const i = index.i.slice(0, -1);
34
39
  return {i};
35
40
  }