@deck.gl/carto 8.8.0-alpha.2 → 8.8.0-alpha.5
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.
- package/dist/dist.dev.js +1752 -1262
- package/dist/es5/api/layer-map.js +17 -5
- package/dist/es5/api/layer-map.js.map +1 -1
- package/dist/es5/api/maps-api-common.js +1 -0
- package/dist/es5/api/maps-api-common.js.map +1 -1
- package/dist/es5/api/parseMap.js +14 -3
- package/dist/es5/api/parseMap.js.map +1 -1
- package/dist/es5/index.js +16 -0
- package/dist/es5/index.js.map +1 -1
- package/dist/es5/layers/carto-layer.js +16 -1
- package/dist/es5/layers/carto-layer.js.map +1 -1
- package/dist/es5/layers/carto-tile-layer.js +17 -12
- package/dist/es5/layers/carto-tile-layer.js.map +1 -1
- package/dist/es5/layers/h3-tile-layer.js +107 -0
- package/dist/es5/layers/h3-tile-layer.js.map +1 -0
- package/dist/es5/layers/h3-tileset-2d.js +175 -0
- package/dist/es5/layers/h3-tileset-2d.js.map +1 -0
- package/dist/es5/layers/quadkey-tile-layer.js +103 -0
- package/dist/es5/layers/quadkey-tile-layer.js.map +1 -0
- package/dist/es5/layers/quadkey-tileset-2d.js +89 -0
- package/dist/es5/layers/quadkey-tileset-2d.js.map +1 -0
- package/dist/es5/layers/schema/carto-tile.js +261 -188
- package/dist/es5/layers/schema/carto-tile.js.map +1 -1
- package/dist/es5/layers/spatial-index-tile-layer.js +92 -0
- package/dist/es5/layers/spatial-index-tile-layer.js.map +1 -0
- package/dist/esm/api/layer-map.js +12 -4
- package/dist/esm/api/layer-map.js.map +1 -1
- package/dist/esm/api/maps-api-common.js +1 -0
- package/dist/esm/api/maps-api-common.js.map +1 -1
- package/dist/esm/api/parseMap.js +15 -4
- package/dist/esm/api/parseMap.js.map +1 -1
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/layers/carto-layer.js +15 -2
- package/dist/esm/layers/carto-layer.js.map +1 -1
- package/dist/esm/layers/carto-tile-layer.js +20 -16
- package/dist/esm/layers/carto-tile-layer.js.map +1 -1
- package/dist/esm/layers/h3-tile-layer.js +69 -0
- package/dist/esm/layers/h3-tile-layer.js.map +1 -0
- package/dist/esm/layers/h3-tileset-2d.js +118 -0
- package/dist/esm/layers/h3-tileset-2d.js.map +1 -0
- package/dist/esm/layers/quadkey-tile-layer.js +63 -0
- package/dist/esm/layers/quadkey-tile-layer.js.map +1 -0
- package/dist/esm/layers/quadkey-tileset-2d.js +48 -0
- package/dist/esm/layers/quadkey-tileset-2d.js.map +1 -0
- package/dist/esm/layers/schema/carto-tile.js +174 -189
- package/dist/esm/layers/schema/carto-tile.js.map +1 -1
- package/dist/esm/layers/spatial-index-tile-layer.js +57 -0
- package/dist/esm/layers/spatial-index-tile-layer.js.map +1 -0
- package/dist.min.js +14 -14
- package/package.json +5 -3
- package/src/api/layer-map.ts +14 -4
- package/src/api/maps-api-common.ts +1 -0
- package/src/api/parseMap.ts +20 -5
- package/src/index.ts +2 -0
- package/src/layers/carto-layer.ts +16 -2
- package/src/layers/{carto-tile-layer.js → carto-tile-layer.ts} +64 -27
- package/src/layers/h3-tile-layer.js +52 -0
- package/src/layers/h3-tileset-2d.js +108 -0
- package/src/layers/quadkey-tile-layer.js +47 -0
- package/src/layers/quadkey-tileset-2d.js +36 -0
- package/src/layers/schema/carto-tile.ts +221 -0
- package/src/layers/spatial-index-tile-layer.js +48 -0
- 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.
|
|
5
|
+
"version": "8.8.0-alpha.5",
|
|
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,7 +36,7 @@
|
|
|
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.
|
|
39
|
+
"@luma.gl/constants": "^8.5.13",
|
|
39
40
|
"@math.gl/web-mercator": "3.6.0-alpha.5",
|
|
40
41
|
"cartocolor": "^4.0.2",
|
|
41
42
|
"d3-array": "^2.8.0",
|
|
@@ -46,6 +47,7 @@
|
|
|
46
47
|
"pbf": "^3.2.1"
|
|
47
48
|
},
|
|
48
49
|
"devDependencies": {
|
|
50
|
+
"@loaders.gl/schema": "^3.2.0-alpha.4",
|
|
49
51
|
"@types/d3-array": "^3.0.2",
|
|
50
52
|
"@types/d3-color": "^1.4.2",
|
|
51
53
|
"@types/d3-scale": "^3.0.0"
|
|
@@ -58,5 +60,5 @@
|
|
|
58
60
|
"@deck.gl/layers": "^8.0.0",
|
|
59
61
|
"@loaders.gl/core": "^3.0.0"
|
|
60
62
|
},
|
|
61
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "a5e210f62321ab78b7cacbcd0614e0ffcdf6bca7"
|
|
62
64
|
}
|
package/src/api/layer-map.ts
CHANGED
|
@@ -42,6 +42,12 @@ export const AGGREGATION = {
|
|
|
42
42
|
sum: 'SUM'
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
+
export const OPACITY_MAP = {
|
|
46
|
+
getFillColor: 'opacity',
|
|
47
|
+
getLineColor: 'strokeOpacity',
|
|
48
|
+
getTextColor: 'opacity'
|
|
49
|
+
};
|
|
50
|
+
|
|
45
51
|
const AGGREGATION_FUNC = {
|
|
46
52
|
'count unique': (values, accessor) => groupSort(values, v => v.length, accessor).length,
|
|
47
53
|
median,
|
|
@@ -71,7 +77,6 @@ const sharedPropMap = {
|
|
|
71
77
|
enable3d: 'extruded',
|
|
72
78
|
elevationScale: 'elevationScale',
|
|
73
79
|
filled: 'filled',
|
|
74
|
-
opacity: 'opacity',
|
|
75
80
|
strokeColor: 'getLineColor',
|
|
76
81
|
stroked: 'stroked',
|
|
77
82
|
thickness: 'getLineWidth',
|
|
@@ -225,6 +230,10 @@ function normalizeAccessor(accessor, data) {
|
|
|
225
230
|
return accessor;
|
|
226
231
|
}
|
|
227
232
|
|
|
233
|
+
export function opacityToAlpha(opacity) {
|
|
234
|
+
return opacity !== undefined ? Math.round(255 * Math.pow(opacity, 1 / 2.2)) : 255;
|
|
235
|
+
}
|
|
236
|
+
|
|
228
237
|
export function getColorValueAccessor({name}, colorAggregation, data: any) {
|
|
229
238
|
const aggregator = AGGREGATION_FUNC[colorAggregation];
|
|
230
239
|
const accessor = values => aggregator(values, p => p[name]);
|
|
@@ -259,11 +268,12 @@ export function getColorAccessor(
|
|
|
259
268
|
scale.domain(domain);
|
|
260
269
|
scale.range(scaleColor);
|
|
261
270
|
scale.unknown(UNKNOWN_COLOR);
|
|
262
|
-
const alpha =
|
|
271
|
+
const alpha = opacityToAlpha(opacity);
|
|
263
272
|
|
|
264
273
|
const accessor = properties => {
|
|
265
|
-
const
|
|
266
|
-
|
|
274
|
+
const propertyValue = properties[name];
|
|
275
|
+
const {r, g, b} = rgb(scale(propertyValue));
|
|
276
|
+
return [r, g, b, propertyValue === null ? 0 : alpha];
|
|
267
277
|
};
|
|
268
278
|
return normalizeAccessor(accessor, data);
|
|
269
279
|
}
|
package/src/api/parseMap.ts
CHANGED
|
@@ -6,7 +6,9 @@ import {
|
|
|
6
6
|
getColorValueAccessor,
|
|
7
7
|
getSizeAccessor,
|
|
8
8
|
getTextAccessor,
|
|
9
|
-
getTextPixelOffsetAccessor
|
|
9
|
+
getTextPixelOffsetAccessor,
|
|
10
|
+
OPACITY_MAP,
|
|
11
|
+
opacityToAlpha
|
|
10
12
|
} from './layer-map';
|
|
11
13
|
import {_flatten as flatten, log} from '@deck.gl/core';
|
|
12
14
|
import {assert} from '../utils';
|
|
@@ -131,10 +133,21 @@ function createStyleProps(config, mapping) {
|
|
|
131
133
|
mapProps(config, result, mapping);
|
|
132
134
|
|
|
133
135
|
// Kepler format sometimes omits strokeColor. TODO: remove once we can rely on
|
|
134
|
-
// `strokeColor` always being
|
|
136
|
+
// `strokeColor` always being set when `stroke: true`.
|
|
135
137
|
if (result.stroked && !result.getLineColor) {
|
|
136
138
|
result.getLineColor = result.getFillColor;
|
|
137
139
|
}
|
|
140
|
+
|
|
141
|
+
for (const colorAccessor in OPACITY_MAP) {
|
|
142
|
+
if (Array.isArray(result[colorAccessor])) {
|
|
143
|
+
const color = [...result[colorAccessor]];
|
|
144
|
+
const opacityKey = OPACITY_MAP[colorAccessor];
|
|
145
|
+
const opacity = config.visConfig[opacityKey];
|
|
146
|
+
color[3] = opacityToAlpha(opacity);
|
|
147
|
+
result[colorAccessor] = color;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
138
151
|
result.highlightColor = config.visConfig.enable3d ? [255, 255, 255, 60] : [252, 242, 26, 255];
|
|
139
152
|
return result;
|
|
140
153
|
}
|
|
@@ -159,7 +172,7 @@ function createChannelProps(visualChannels, type, config, data) {
|
|
|
159
172
|
if (!AGGREGATION[colorAggregation]) {
|
|
160
173
|
result.getColorValue = getColorValueAccessor(colorField, colorAggregation, data);
|
|
161
174
|
} else {
|
|
162
|
-
result.getColorWeight = d => [colorField.name];
|
|
175
|
+
result.getColorWeight = d => d[colorField.name];
|
|
163
176
|
}
|
|
164
177
|
}
|
|
165
178
|
} else if (colorField) {
|
|
@@ -167,13 +180,15 @@ function createChannelProps(visualChannels, type, config, data) {
|
|
|
167
180
|
colorField,
|
|
168
181
|
colorScale,
|
|
169
182
|
visConfig.colorRange,
|
|
170
|
-
|
|
183
|
+
visConfig.opacity,
|
|
171
184
|
data
|
|
172
185
|
);
|
|
173
186
|
}
|
|
174
187
|
|
|
175
188
|
if (strokeColorField) {
|
|
176
|
-
const
|
|
189
|
+
const fallbackOpacity = type === 'point' ? visConfig.opacity : 1;
|
|
190
|
+
const opacity =
|
|
191
|
+
visConfig.strokeOpacity !== undefined ? visConfig.strokeOpacity : fallbackOpacity;
|
|
177
192
|
result.getLineColor = getColorAccessor(
|
|
178
193
|
strokeColorField,
|
|
179
194
|
strokeColorScale,
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export {getDefaultCredentials, setDefaultCredentials} from './config';
|
|
2
2
|
export {default as CartoLayer} from './layers/carto-layer';
|
|
3
3
|
export {default as _CartoTileLayer} from './layers/carto-tile-layer';
|
|
4
|
+
export {default as _H3TileLayer} from './layers/h3-tile-layer';
|
|
5
|
+
export {default as _QuadkeyTileLayer} from './layers/quadkey-tile-layer';
|
|
4
6
|
export {default as BASEMAP} from './basemap';
|
|
5
7
|
export {default as colorBins} from './style/color-bins-style';
|
|
6
8
|
export {default as colorCategories} from './style/color-categories-style';
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import {CompositeLayer, Layer, log} from '@deck.gl/core';
|
|
2
2
|
import CartoTileLayer from './carto-tile-layer';
|
|
3
|
+
import H3TileLayer from './h3-tile-layer';
|
|
4
|
+
import QuadkeyTileLayer from './quadkey-tile-layer';
|
|
3
5
|
import {MVTLayer} from '@deck.gl/geo-layers';
|
|
4
6
|
import {GeoJsonLayer} from '@deck.gl/layers';
|
|
5
7
|
import {fetchLayerData, getDataV2, API_VERSIONS} from '../api';
|
|
@@ -55,7 +57,13 @@ const defaultProps = {
|
|
|
55
57
|
geoColumn: null,
|
|
56
58
|
|
|
57
59
|
// (Array<String>, optional): names of columns to fetch. By default, all columns are fetched.
|
|
58
|
-
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
|
|
59
67
|
};
|
|
60
68
|
|
|
61
69
|
export interface CartoLayerProps<DataT = any> extends CompositeLayerProps<DataT> {
|
|
@@ -240,7 +248,7 @@ export default class CartoLayer<DataT = any> extends CompositeLayer<CartoLayerPr
|
|
|
240
248
|
source,
|
|
241
249
|
clientId,
|
|
242
250
|
credentials: credentials as CloudNativeCredentials,
|
|
243
|
-
connection
|
|
251
|
+
connection,
|
|
244
252
|
...rest
|
|
245
253
|
});
|
|
246
254
|
}
|
|
@@ -283,6 +291,12 @@ export default class CartoLayer<DataT = any> extends CompositeLayer<CartoLayerPr
|
|
|
283
291
|
(tileUrl.searchParams.get('formatTiles') as TileFormat) ||
|
|
284
292
|
TILE_FORMATS.MVT;
|
|
285
293
|
|
|
294
|
+
if (data.scheme === 'h3') {
|
|
295
|
+
return [H3TileLayer, props];
|
|
296
|
+
}
|
|
297
|
+
if (data.scheme === 'quadkey') {
|
|
298
|
+
return [QuadkeyTileLayer, props];
|
|
299
|
+
}
|
|
286
300
|
return props.formatTiles === TILE_FORMATS.MVT ? [MVTLayer, props] : [CartoTileLayer, props];
|
|
287
301
|
}
|
|
288
302
|
|
|
@@ -1,29 +1,39 @@
|
|
|
1
1
|
/* global TextDecoder */
|
|
2
2
|
import Protobuf from 'pbf';
|
|
3
|
-
import {log} from '@deck.gl/core';
|
|
3
|
+
import {Layer, LayersList, log} from '@deck.gl/core';
|
|
4
4
|
import {ClipExtension} from '@deck.gl/extensions';
|
|
5
|
-
import {
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
77
|
-
|
|
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(
|
|
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.
|
|
148
|
+
const tileBbox = props.tile.bbox as any;
|
|
149
|
+
const {west, south, east, north} = tileBbox;
|
|
109
150
|
|
|
110
|
-
const {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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,52 @@
|
|
|
1
|
+
import {CompositeLayer} from '@deck.gl/core';
|
|
2
|
+
import {H3HexagonLayer} from '@deck.gl/geo-layers';
|
|
3
|
+
import H3Tileset2D from './h3-tileset-2d';
|
|
4
|
+
import SpatialIndexTileLayer from './spatial-index-tile-layer';
|
|
5
|
+
|
|
6
|
+
const renderSubLayers = props => {
|
|
7
|
+
const {data} = props;
|
|
8
|
+
const {index} = props.tile;
|
|
9
|
+
if (!data || !data.length) return null;
|
|
10
|
+
|
|
11
|
+
return new H3HexagonLayer(props, {
|
|
12
|
+
centerHexagon: index,
|
|
13
|
+
highPrecision: true
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const defaultProps = {
|
|
18
|
+
aggregationResLevel: 4
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export default class H3TileLayer extends CompositeLayer {
|
|
22
|
+
initializeState() {
|
|
23
|
+
this.setState({data: null, tileJSON: null});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
updateState({props, oldProps, context, changeFlags}) {
|
|
27
|
+
if (changeFlags.dataChanged) {
|
|
28
|
+
let {data} = this.props;
|
|
29
|
+
const tileJSON = data;
|
|
30
|
+
data = tileJSON.tiles;
|
|
31
|
+
this.setState({data, tileJSON});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
renderLayers() {
|
|
36
|
+
const {data, tileJSON} = this.state;
|
|
37
|
+
const maxZoom = parseInt(tileJSON.maxresolution);
|
|
38
|
+
return [
|
|
39
|
+
new SpatialIndexTileLayer(this.props, {
|
|
40
|
+
id: `h3-tile-layer-${this.props.id}`,
|
|
41
|
+
data,
|
|
42
|
+
getHexagon: d => d.id,
|
|
43
|
+
TilesetClass: H3Tileset2D,
|
|
44
|
+
renderSubLayers,
|
|
45
|
+
maxZoom
|
|
46
|
+
})
|
|
47
|
+
];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
H3TileLayer.layerName = 'H3TileLayer';
|
|
52
|
+
H3TileLayer.defaultProps = defaultProps;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import {_Tileset2D as Tileset2D} 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
|
+
function getHexagonsInBoundingBox({west, north, east, south}, resolution) {
|
|
13
|
+
if (resolution === 0) {
|
|
14
|
+
return getRes0Indexes();
|
|
15
|
+
}
|
|
16
|
+
if (east - west > 180) {
|
|
17
|
+
// This is a known issue in h3-js: polyfill does not work correctly
|
|
18
|
+
// when longitude span is larger than 180 degrees.
|
|
19
|
+
return getHexagonsInBoundingBox({west, north, east: 0, south}, resolution).concat(
|
|
20
|
+
getHexagonsInBoundingBox({west: 0, north, east, south}, resolution)
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// `polyfill()` fills based on hexagon center, which means tiles vanish
|
|
25
|
+
// prematurely. Get more accurate coverage by oversampling
|
|
26
|
+
const oversample = 2;
|
|
27
|
+
const h3Indices = polyfill(
|
|
28
|
+
[
|
|
29
|
+
[
|
|
30
|
+
[west, north],
|
|
31
|
+
[west, south],
|
|
32
|
+
[east, south],
|
|
33
|
+
[east, north],
|
|
34
|
+
[west, north]
|
|
35
|
+
]
|
|
36
|
+
],
|
|
37
|
+
resolution + oversample,
|
|
38
|
+
true
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
return oversample ? [...new Set(h3Indices.map(i => h3ToParent(i, resolution)))] : h3Indices;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function tileToBoundingBox(index) {
|
|
45
|
+
const coordinates = h3ToGeoBoundary(index);
|
|
46
|
+
const latitudes = coordinates.map(c => c[0]);
|
|
47
|
+
const longitudes = coordinates.map(c => c[1]);
|
|
48
|
+
const west = Math.min(...longitudes);
|
|
49
|
+
const south = Math.min(...latitudes);
|
|
50
|
+
const east = Math.max(...longitudes);
|
|
51
|
+
const north = Math.max(...latitudes);
|
|
52
|
+
return {west, south, east, north};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Resolution conversion function. Takes a WebMercatorViewport and returns
|
|
56
|
+
// a H3 resolution such that the screen space size of the hexagons is
|
|
57
|
+
// similar
|
|
58
|
+
// Relative scale factor (0 = no biasing, 2 = a few hexagons cover view)
|
|
59
|
+
const BIAS = 2;
|
|
60
|
+
function getHexagonResolution(viewport) {
|
|
61
|
+
const hexagonScaleFactor = (2 / 3) * viewport.zoom;
|
|
62
|
+
const latitudeScaleFactor = Math.log(1 / Math.cos((Math.PI * viewport.latitude) / 180));
|
|
63
|
+
|
|
64
|
+
// Clip and bias
|
|
65
|
+
return Math.max(0, Math.floor(hexagonScaleFactor + latitudeScaleFactor - BIAS));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export default class H3Tileset2D extends Tileset2D {
|
|
69
|
+
getTileIndices({viewport, minZoom, maxZoom}) {
|
|
70
|
+
const [east, south, west, north] = viewport.getBounds();
|
|
71
|
+
|
|
72
|
+
let z = getHexagonResolution(viewport);
|
|
73
|
+
let indices = [];
|
|
74
|
+
if (typeof minZoom === 'number' && Number.isFinite(minZoom) && z < minZoom) {
|
|
75
|
+
z = minZoom;
|
|
76
|
+
}
|
|
77
|
+
if (typeof maxZoom === 'number' && Number.isFinite(maxZoom) && z > maxZoom) {
|
|
78
|
+
z = maxZoom;
|
|
79
|
+
|
|
80
|
+
// Once we are at max zoom, getHexagonsInBoundingBox doesn't work, simply
|
|
81
|
+
// get a ring centered on the hexagon in the viewport center
|
|
82
|
+
const center = geoToH3(viewport.latitude, viewport.longitude, maxZoom);
|
|
83
|
+
indices = kRing(center, 1);
|
|
84
|
+
} else {
|
|
85
|
+
indices = getHexagonsInBoundingBox({west, north, east, south}, z);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return indices.map(i => ({i}));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
getTileId({i}) {
|
|
92
|
+
return i;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
getTileMetadata({i}) {
|
|
96
|
+
return {bbox: tileToBoundingBox(i)};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
getTileZoom({i}) {
|
|
100
|
+
return h3GetResolution(i);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
getParentIndex(index) {
|
|
104
|
+
const resolution = h3GetResolution(index.i);
|
|
105
|
+
const i = h3ToParent(index.i, resolution - 1);
|
|
106
|
+
return {i};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import {CompositeLayer} from '@deck.gl/core';
|
|
2
|
+
import {QuadkeyLayer} from '@deck.gl/geo-layers';
|
|
3
|
+
import QuadkeyTileset2D from './quadkey-tileset-2d';
|
|
4
|
+
import SpatialIndexTileLayer from './spatial-index-tile-layer';
|
|
5
|
+
|
|
6
|
+
const renderSubLayers = props => {
|
|
7
|
+
const {data} = props;
|
|
8
|
+
if (!data || !data.length) return null;
|
|
9
|
+
return new QuadkeyLayer(props);
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const defaultProps = {
|
|
13
|
+
aggregationResLevel: 6
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default class QuadkeyTileLayer extends CompositeLayer {
|
|
17
|
+
initializeState() {
|
|
18
|
+
this.setState({data: null, tileJSON: null});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
updateState({props, oldProps, context, changeFlags}) {
|
|
22
|
+
if (changeFlags.dataChanged) {
|
|
23
|
+
let {data} = this.props;
|
|
24
|
+
const tileJSON = data;
|
|
25
|
+
data = tileJSON.tiles;
|
|
26
|
+
this.setState({data, tileJSON});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
renderLayers() {
|
|
31
|
+
const {data, tileJSON} = this.state;
|
|
32
|
+
const maxZoom = parseInt(tileJSON.maxresolution);
|
|
33
|
+
return [
|
|
34
|
+
new SpatialIndexTileLayer(this.props, {
|
|
35
|
+
id: `quadkey-tile-layer-${this.props.id}`,
|
|
36
|
+
data,
|
|
37
|
+
getQuadkey: d => d.id,
|
|
38
|
+
TilesetClass: QuadkeyTileset2D,
|
|
39
|
+
renderSubLayers,
|
|
40
|
+
maxZoom
|
|
41
|
+
})
|
|
42
|
+
];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
QuadkeyTileLayer.layerName = 'QuadkeyTileLayer';
|
|
47
|
+
QuadkeyTileLayer.defaultProps = defaultProps;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {_Tileset2D as Tileset2D} from '@deck.gl/geo-layers';
|
|
2
|
+
|
|
3
|
+
function tileToQuadkey(tile) {
|
|
4
|
+
let index = '';
|
|
5
|
+
for (let z = tile.z; z > 0; z--) {
|
|
6
|
+
let b = 0;
|
|
7
|
+
const mask = 1 << (z - 1);
|
|
8
|
+
if ((tile.x & mask) !== 0) b++;
|
|
9
|
+
if ((tile.y & mask) !== 0) b += 2;
|
|
10
|
+
index += b.toString();
|
|
11
|
+
}
|
|
12
|
+
return {i: index};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default class QuadkeyTileset2D extends Tileset2D {
|
|
16
|
+
getTileIndices(opts) {
|
|
17
|
+
return super.getTileIndices(opts).map(tileToQuadkey);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
getTileId({i}) {
|
|
21
|
+
return i;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
getTileMetadata() {
|
|
25
|
+
return {};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
getTileZoom({i}) {
|
|
29
|
+
return i.length;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
getParentIndex(index) {
|
|
33
|
+
const i = index.i.slice(0, -1);
|
|
34
|
+
return {i};
|
|
35
|
+
}
|
|
36
|
+
}
|