@deck.gl/carto 8.8.3 → 8.8.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.
- package/dist/dist.dev.js +1382 -1153
- package/dist/es5/api/index.js.map +1 -1
- package/dist/es5/api/layer-map.js +104 -17
- package/dist/es5/api/layer-map.js.map +1 -1
- package/dist/es5/api/maps-api-common.js.map +1 -1
- package/dist/es5/api/maps-v3-client.js +213 -47
- package/dist/es5/api/maps-v3-client.js.map +1 -1
- package/dist/es5/api/parseMap.js +14 -4
- package/dist/es5/api/parseMap.js.map +1 -1
- package/dist/es5/config.js +11 -2
- package/dist/es5/config.js.map +1 -1
- package/dist/es5/index.js.map +1 -1
- package/dist/es5/layers/carto-layer.js +10 -23
- package/dist/es5/layers/carto-layer.js.map +1 -1
- package/dist/es5/style/color-bins-style.js.map +1 -1
- package/dist/es5/style/color-categories-style.js.map +1 -1
- package/dist/es5/style/color-continuous-style.js.map +1 -1
- package/dist/es5/style/utils.js +3 -1
- package/dist/es5/style/utils.js.map +1 -1
- package/dist/esm/api/index.js.map +1 -1
- package/dist/esm/api/layer-map.js +79 -14
- package/dist/esm/api/layer-map.js.map +1 -1
- package/dist/esm/api/maps-api-common.js.map +1 -1
- package/dist/esm/api/maps-v3-client.js +111 -11
- package/dist/esm/api/maps-v3-client.js.map +1 -1
- package/dist/esm/api/parseMap.js +18 -4
- package/dist/esm/api/parseMap.js.map +1 -1
- package/dist/esm/config.js +10 -2
- package/dist/esm/config.js.map +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/layers/carto-layer.js +7 -19
- package/dist/esm/layers/carto-layer.js.map +1 -1
- package/dist/esm/style/color-bins-style.js.map +1 -1
- package/dist/esm/style/color-categories-style.js.map +1 -1
- package/dist/esm/style/color-continuous-style.js.map +1 -1
- package/dist/esm/style/utils.js +3 -1
- package/dist/esm/style/utils.js.map +1 -1
- package/dist.min.js +138 -138
- package/package.json +9 -9
- package/src/api/index.ts +1 -0
- package/src/api/layer-map.ts +76 -13
- package/src/api/maps-api-common.ts +8 -0
- package/src/api/maps-v3-client.ts +116 -12
- package/src/api/parseMap.ts +6 -2
- package/src/config.ts +12 -2
- package/src/index.ts +1 -1
- package/src/layers/carto-layer.ts +19 -32
- package/src/style/color-bins-style.ts +25 -3
- package/src/style/color-categories-style.ts +28 -4
- package/src/style/color-continuous-style.ts +25 -3
- package/src/style/utils.ts +8 -4
- package/typed/api/index.d.ts +1 -0
- package/typed/api/index.d.ts.map +1 -1
- package/typed/api/layer-map.d.ts +12 -4
- package/typed/api/layer-map.d.ts.map +1 -1
- package/typed/api/maps-api-common.d.ts +4 -0
- package/typed/api/maps-api-common.d.ts.map +1 -1
- package/typed/api/maps-v3-client.d.ts +4 -3
- package/typed/api/maps-v3-client.d.ts.map +1 -1
- package/typed/config.d.ts +2 -0
- package/typed/config.d.ts.map +1 -1
- package/typed/index.d.ts +1 -0
- package/typed/index.d.ts.map +1 -1
- package/typed/layers/carto-layer.d.ts +5 -8
- package/typed/layers/carto-layer.d.ts.map +1 -1
- package/typed/style/color-bins-style.d.ts +22 -3
- package/typed/style/color-bins-style.d.ts.map +1 -1
- package/typed/style/color-categories-style.d.ts +24 -4
- package/typed/style/color-categories-style.d.ts.map +1 -1
- package/typed/style/color-continuous-style.d.ts +22 -3
- package/typed/style/color-continuous-style.d.ts.map +1 -1
- package/typed/style/utils.d.ts +3 -6
- package/typed/style/utils.d.ts.map +1 -1
- package/typed/api/index.js +0 -3
- package/typed/api/layer-map.js +0 -264
- package/typed/api/maps-api-common.js +0 -50
- package/typed/api/maps-client.js +0 -125
- package/typed/api/maps-v3-client.js +0 -304
- package/typed/api/parseMap.js +0 -178
- package/typed/basemap.js +0 -9
- package/typed/config.js +0 -35
- package/typed/index.js +0 -10
- package/typed/layers/carto-layer.js +0 -173
- package/typed/layers/carto-tile-layer.js +0 -105
- package/typed/layers/h3-tile-layer.js +0 -47
- package/typed/layers/h3-tileset-2d.js +0 -85
- package/typed/layers/quadkey-tile-layer.js +0 -42
- package/typed/layers/quadkey-tileset-2d.js +0 -36
- package/typed/layers/schema/carto-tile.js +0 -161
- package/typed/layers/spatial-index-tile-layer.js +0 -40
- package/typed/style/color-bins-style.js +0 -12
- package/typed/style/color-categories-style.js +0 -16
- package/typed/style/color-continuous-style.js +0 -12
- package/typed/style/palette.js +0 -62
- package/typed/style/utils.js +0 -15
- package/typed/utils.js +0 -4
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.
|
|
5
|
+
"version": "8.8.6",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
8
8
|
},
|
|
@@ -32,12 +32,12 @@
|
|
|
32
32
|
"prepublishOnly": "npm run build-bundle && npm run build-bundle -- --env.dev"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@loaders.gl/gis": "^3.2.
|
|
36
|
-
"@loaders.gl/loader-utils": "^3.2.
|
|
37
|
-
"@loaders.gl/mvt": "^3.2.
|
|
38
|
-
"@loaders.gl/tiles": "^3.2.
|
|
39
|
-
"@luma.gl/constants": "^8.5.
|
|
40
|
-
"@math.gl/web-mercator": "^3.6.
|
|
35
|
+
"@loaders.gl/gis": "^3.2.5",
|
|
36
|
+
"@loaders.gl/loader-utils": "^3.2.5",
|
|
37
|
+
"@loaders.gl/mvt": "^3.2.5",
|
|
38
|
+
"@loaders.gl/tiles": "^3.2.5",
|
|
39
|
+
"@luma.gl/constants": "^8.5.16",
|
|
40
|
+
"@math.gl/web-mercator": "^3.6.2",
|
|
41
41
|
"cartocolor": "^4.0.2",
|
|
42
42
|
"d3-array": "^2.8.0",
|
|
43
43
|
"d3-color": "^2.0.0",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"pbf": "^3.2.1"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@loaders.gl/schema": "^3.2.
|
|
51
|
+
"@loaders.gl/schema": "^3.2.5",
|
|
52
52
|
"@types/d3-array": "^3.0.2",
|
|
53
53
|
"@types/d3-color": "^1.4.2",
|
|
54
54
|
"@types/d3-scale": "^3.0.0"
|
|
@@ -61,5 +61,5 @@
|
|
|
61
61
|
"@deck.gl/layers": "^8.0.0",
|
|
62
62
|
"@loaders.gl/core": "^3.0.0"
|
|
63
63
|
},
|
|
64
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "a0e9fda8ed34ad91a6b25451c8df290ae025028f"
|
|
65
65
|
}
|
package/src/api/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export {FORMATS, TILE_FORMATS, MAP_TYPES, API_VERSIONS} from './maps-api-common';
|
|
2
|
+
export type {QueryParameters} from './maps-api-common';
|
|
2
3
|
export {getDataV2, CONNECTIONS} from './maps-client';
|
|
3
4
|
export {fetchLayerData, fetchMap, mapInstantiation} from './maps-v3-client';
|
package/src/api/layer-map.ts
CHANGED
|
@@ -19,6 +19,8 @@ import {GeoJsonLayer} from '@deck.gl/layers';
|
|
|
19
19
|
import {H3HexagonLayer, MVTLayer} from '@deck.gl/geo-layers';
|
|
20
20
|
|
|
21
21
|
import CartoTileLayer from '../layers/carto-tile-layer';
|
|
22
|
+
import H3TileLayer from '../layers/h3-tile-layer';
|
|
23
|
+
import QuadbinTileLayer from '../layers/quadbin-tile-layer';
|
|
22
24
|
import {TILE_FORMATS} from './maps-api-common';
|
|
23
25
|
import {assert} from '../utils';
|
|
24
26
|
|
|
@@ -111,7 +113,7 @@ export function getLayer(
|
|
|
111
113
|
config,
|
|
112
114
|
dataset
|
|
113
115
|
): {Layer: ConstructorOf<Layer>; propMap: any; defaultProps: any} {
|
|
114
|
-
if (type === 'mvt' || type === 'tileset') {
|
|
116
|
+
if (type === 'mvt' || type === 'tileset' || type === 'h3' || type === 'quadbin') {
|
|
115
117
|
return getTileLayer(dataset);
|
|
116
118
|
}
|
|
117
119
|
|
|
@@ -163,31 +165,58 @@ export function getLayer(
|
|
|
163
165
|
};
|
|
164
166
|
}
|
|
165
167
|
|
|
168
|
+
export function layerFromTileDataset(
|
|
169
|
+
formatTiles: string | null = TILE_FORMATS.MVT,
|
|
170
|
+
scheme: string
|
|
171
|
+
): typeof CartoTileLayer | typeof H3TileLayer | typeof MVTLayer | typeof QuadbinTileLayer {
|
|
172
|
+
if (scheme === 'h3') {
|
|
173
|
+
return H3TileLayer;
|
|
174
|
+
}
|
|
175
|
+
if (scheme === 'quadbin') {
|
|
176
|
+
return QuadbinTileLayer;
|
|
177
|
+
}
|
|
178
|
+
if (formatTiles === TILE_FORMATS.MVT) {
|
|
179
|
+
return MVTLayer;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// formatTiles === BINARY|JSON|GEOJSON
|
|
183
|
+
return CartoTileLayer;
|
|
184
|
+
}
|
|
185
|
+
|
|
166
186
|
function getTileLayer(dataset) {
|
|
167
187
|
const {
|
|
188
|
+
aggregationExp,
|
|
189
|
+
aggregationResLevel,
|
|
168
190
|
data: {
|
|
191
|
+
scheme,
|
|
169
192
|
tiles: [tileUrl]
|
|
170
193
|
}
|
|
171
194
|
} = dataset;
|
|
172
195
|
/* global URL */
|
|
173
|
-
const formatTiles = new URL(tileUrl).searchParams.get('formatTiles')
|
|
196
|
+
const formatTiles = new URL(tileUrl).searchParams.get('formatTiles');
|
|
174
197
|
|
|
175
198
|
return {
|
|
176
|
-
Layer: formatTiles
|
|
199
|
+
Layer: layerFromTileDataset(formatTiles, scheme),
|
|
177
200
|
propMap: sharedPropMap,
|
|
178
201
|
defaultProps: {
|
|
179
202
|
...defaultProps,
|
|
180
|
-
|
|
181
|
-
|
|
203
|
+
...(aggregationExp && {aggregationExp}),
|
|
204
|
+
...(aggregationResLevel && {aggregationResLevel}),
|
|
205
|
+
formatTiles,
|
|
206
|
+
uniqueIdProperty: 'geoid'
|
|
182
207
|
}
|
|
183
208
|
};
|
|
184
209
|
}
|
|
185
210
|
|
|
186
|
-
function domainFromAttribute(attribute, scaleType: SCALE_TYPE) {
|
|
211
|
+
function domainFromAttribute(attribute, scaleType: SCALE_TYPE, scaleLength: number) {
|
|
187
212
|
if (scaleType === 'ordinal' || scaleType === 'point') {
|
|
188
213
|
return attribute.categories.map(c => c.category).filter(c => c !== undefined && c !== null);
|
|
189
214
|
}
|
|
190
215
|
|
|
216
|
+
if (scaleType === 'quantile' && attribute.quantiles) {
|
|
217
|
+
return attribute.quantiles[scaleLength];
|
|
218
|
+
}
|
|
219
|
+
|
|
191
220
|
let {min} = attribute;
|
|
192
221
|
if (scaleType === 'log' && min === 0) {
|
|
193
222
|
min = 1e-5;
|
|
@@ -211,12 +240,12 @@ function domainFromValues(values, scaleType: SCALE_TYPE) {
|
|
|
211
240
|
return extent(values);
|
|
212
241
|
}
|
|
213
242
|
|
|
214
|
-
function calculateDomain(data, name, scaleType) {
|
|
243
|
+
function calculateDomain(data, name, scaleType, scaleLength?) {
|
|
215
244
|
if (data.tilestats) {
|
|
216
245
|
// Tileset data type
|
|
217
246
|
const {attributes} = data.tilestats.layers[0];
|
|
218
247
|
const attribute = attributes.find(a => a.attribute === name);
|
|
219
|
-
return domainFromAttribute(attribute, scaleType);
|
|
248
|
+
return domainFromAttribute(attribute, scaleType, scaleLength);
|
|
220
249
|
} else if (data.features) {
|
|
221
250
|
// GeoJSON data type
|
|
222
251
|
const values = data.features.map(({properties}) => properties[name]);
|
|
@@ -243,6 +272,25 @@ export function opacityToAlpha(opacity) {
|
|
|
243
272
|
return opacity !== undefined ? Math.round(255 * Math.pow(opacity, 1 / 2.2)) : 255;
|
|
244
273
|
}
|
|
245
274
|
|
|
275
|
+
function getAccessorKeys(name: string, aggregation: string | undefined): string[] {
|
|
276
|
+
let keys = [name];
|
|
277
|
+
if (aggregation) {
|
|
278
|
+
// Snowflake will capitalized the keys, need to check lower and upper case version
|
|
279
|
+
keys = keys.concat([aggregation, aggregation.toUpperCase()].map(a => `${name}_${a}`));
|
|
280
|
+
}
|
|
281
|
+
return keys;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function findAccessorKey(keys: string[], properties): string[] {
|
|
285
|
+
for (const key of keys) {
|
|
286
|
+
if (key in properties) {
|
|
287
|
+
return [key];
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
throw new Error(`Could not find property for any accessor key: ${keys}`);
|
|
292
|
+
}
|
|
293
|
+
|
|
246
294
|
export function getColorValueAccessor({name}, colorAggregation, data: any) {
|
|
247
295
|
const aggregator = AGGREGATION_FUNC[colorAggregation];
|
|
248
296
|
const accessor = values => aggregator(values, p => p[name]);
|
|
@@ -252,7 +300,7 @@ export function getColorValueAccessor({name}, colorAggregation, data: any) {
|
|
|
252
300
|
export function getColorAccessor(
|
|
253
301
|
{name},
|
|
254
302
|
scaleType: SCALE_TYPE,
|
|
255
|
-
{colors, colorMap},
|
|
303
|
+
{aggregation, range: {colors, colorMap}},
|
|
256
304
|
opacity: number | undefined,
|
|
257
305
|
data: any
|
|
258
306
|
) {
|
|
@@ -266,7 +314,7 @@ export function getColorAccessor(
|
|
|
266
314
|
scaleColor.push(color);
|
|
267
315
|
});
|
|
268
316
|
} else {
|
|
269
|
-
domain = calculateDomain(data, name, scaleType);
|
|
317
|
+
domain = calculateDomain(data, name, scaleType, colors.length);
|
|
270
318
|
scaleColor = colors;
|
|
271
319
|
}
|
|
272
320
|
|
|
@@ -279,21 +327,36 @@ export function getColorAccessor(
|
|
|
279
327
|
scale.unknown(UNKNOWN_COLOR);
|
|
280
328
|
const alpha = opacityToAlpha(opacity);
|
|
281
329
|
|
|
330
|
+
let accessorKeys = getAccessorKeys(name, aggregation);
|
|
282
331
|
const accessor = properties => {
|
|
283
|
-
|
|
332
|
+
if (!(accessorKeys[0] in properties)) {
|
|
333
|
+
accessorKeys = findAccessorKey(accessorKeys, properties);
|
|
334
|
+
}
|
|
335
|
+
const propertyValue = properties[accessorKeys[0]];
|
|
284
336
|
const {r, g, b} = rgb(scale(propertyValue));
|
|
285
337
|
return [r, g, b, propertyValue === null ? 0 : alpha];
|
|
286
338
|
};
|
|
287
339
|
return normalizeAccessor(accessor, data);
|
|
288
340
|
}
|
|
289
341
|
|
|
290
|
-
export function getSizeAccessor(
|
|
342
|
+
export function getSizeAccessor(
|
|
343
|
+
{name},
|
|
344
|
+
scaleType: SCALE_TYPE,
|
|
345
|
+
aggregation,
|
|
346
|
+
range: Iterable<Range>,
|
|
347
|
+
data: any
|
|
348
|
+
) {
|
|
291
349
|
const scale = SCALE_FUNCS[scaleType as any]();
|
|
292
350
|
scale.domain(calculateDomain(data, name, scaleType));
|
|
293
351
|
scale.range(range);
|
|
294
352
|
|
|
353
|
+
let accessorKeys = getAccessorKeys(name, aggregation);
|
|
295
354
|
const accessor = properties => {
|
|
296
|
-
|
|
355
|
+
if (!(accessorKeys[0] in properties)) {
|
|
356
|
+
accessorKeys = findAccessorKey(accessorKeys, properties);
|
|
357
|
+
}
|
|
358
|
+
const propertyValue = properties[accessorKeys[0]];
|
|
359
|
+
return scale(propertyValue);
|
|
297
360
|
};
|
|
298
361
|
return normalizeAccessor(accessor, data);
|
|
299
362
|
}
|
|
@@ -77,3 +77,11 @@ type MapInstantiationFormats = Record<
|
|
|
77
77
|
export function encodeParameter(name: string, value: string | boolean | number): string {
|
|
78
78
|
return `${name}=${encodeURIComponent(value)}`;
|
|
79
79
|
}
|
|
80
|
+
|
|
81
|
+
export type QueryParameterValue = string | number | boolean | Array<QueryParameterValue> | object;
|
|
82
|
+
|
|
83
|
+
export type NamedQueryParameter = Record<string, QueryParameterValue>;
|
|
84
|
+
|
|
85
|
+
export type PositionalQueryParameter = QueryParameterValue[];
|
|
86
|
+
|
|
87
|
+
export type QueryParameters = NamedQueryParameter | PositionalQueryParameter;
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Maps API Client for Carto 3
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
getDefaultCredentials,
|
|
6
|
+
buildMapsUrlFromBase,
|
|
7
|
+
buildStatsUrlFromBase,
|
|
8
|
+
CloudNativeCredentials
|
|
9
|
+
} from '../config';
|
|
5
10
|
import {
|
|
6
11
|
API_VERSIONS,
|
|
7
12
|
COLUMNS_SUPPORT,
|
|
@@ -12,6 +17,7 @@ import {
|
|
|
12
17
|
MapInstantiation,
|
|
13
18
|
MapType,
|
|
14
19
|
MAP_TYPES,
|
|
20
|
+
QueryParameters,
|
|
15
21
|
SchemaField,
|
|
16
22
|
TileFormat,
|
|
17
23
|
TILE_FORMATS
|
|
@@ -117,6 +123,7 @@ type FetchLayerDataParams = {
|
|
|
117
123
|
formatTiles?: TileFormat;
|
|
118
124
|
aggregationExp?: string;
|
|
119
125
|
aggregationResLevel?: number;
|
|
126
|
+
queryParameters?: QueryParameters;
|
|
120
127
|
};
|
|
121
128
|
|
|
122
129
|
/**
|
|
@@ -129,13 +136,18 @@ function getParameters({
|
|
|
129
136
|
columns,
|
|
130
137
|
clientId,
|
|
131
138
|
aggregationExp,
|
|
132
|
-
aggregationResLevel
|
|
139
|
+
aggregationResLevel,
|
|
140
|
+
queryParameters
|
|
133
141
|
}: Omit<FetchLayerDataParams, 'connection' | 'credentials'>) {
|
|
134
142
|
const parameters = [encodeParameter('client', clientId || DEFAULT_CLIENT)];
|
|
135
143
|
|
|
136
144
|
const sourceName = type === MAP_TYPES.QUERY ? 'q' : 'name';
|
|
137
145
|
parameters.push(encodeParameter(sourceName, source));
|
|
138
146
|
|
|
147
|
+
if (queryParameters) {
|
|
148
|
+
parameters.push(encodeParameter('queryParameters', JSON.stringify(queryParameters)));
|
|
149
|
+
}
|
|
150
|
+
|
|
139
151
|
if (geoColumn) {
|
|
140
152
|
parameters.push(encodeParameter('geo_column', geoColumn));
|
|
141
153
|
}
|
|
@@ -144,6 +156,9 @@ function getParameters({
|
|
|
144
156
|
}
|
|
145
157
|
if (aggregationExp) {
|
|
146
158
|
parameters.push(encodeParameter('aggregationExp', aggregationExp));
|
|
159
|
+
} else if (isSpatialIndexGeoColumn(geoColumn)) {
|
|
160
|
+
// Default aggregationExp required for spatial index layers
|
|
161
|
+
parameters.push(encodeParameter('aggregationExp', '1 AS value'));
|
|
147
162
|
}
|
|
148
163
|
if (aggregationResLevel) {
|
|
149
164
|
parameters.push(encodeParameter('aggregationResLevel', aggregationResLevel));
|
|
@@ -152,6 +167,11 @@ function getParameters({
|
|
|
152
167
|
return parameters.join('&');
|
|
153
168
|
}
|
|
154
169
|
|
|
170
|
+
function isSpatialIndexGeoColumn(geoColumn: string | undefined) {
|
|
171
|
+
const spatialIndex = geoColumn?.split(':')[0];
|
|
172
|
+
return spatialIndex === 'h3' || spatialIndex === 'quadbin';
|
|
173
|
+
}
|
|
174
|
+
|
|
155
175
|
export async function mapInstantiation({
|
|
156
176
|
type,
|
|
157
177
|
source,
|
|
@@ -161,7 +181,8 @@ export async function mapInstantiation({
|
|
|
161
181
|
columns,
|
|
162
182
|
clientId,
|
|
163
183
|
aggregationExp,
|
|
164
|
-
aggregationResLevel
|
|
184
|
+
aggregationResLevel,
|
|
185
|
+
queryParameters
|
|
165
186
|
}: FetchLayerDataParams): Promise<MapInstantiation> {
|
|
166
187
|
const baseUrl = `${credentials.mapsUrl}/${connection}/${type}`;
|
|
167
188
|
const url = `${baseUrl}?${getParameters({
|
|
@@ -170,8 +191,9 @@ export async function mapInstantiation({
|
|
|
170
191
|
geoColumn,
|
|
171
192
|
columns,
|
|
172
193
|
clientId,
|
|
194
|
+
aggregationResLevel,
|
|
173
195
|
aggregationExp,
|
|
174
|
-
|
|
196
|
+
queryParameters
|
|
175
197
|
})}`;
|
|
176
198
|
const {accessToken} = credentials;
|
|
177
199
|
|
|
@@ -179,7 +201,8 @@ export async function mapInstantiation({
|
|
|
179
201
|
// need to be a POST request
|
|
180
202
|
const body = JSON.stringify({
|
|
181
203
|
q: source,
|
|
182
|
-
client: clientId || DEFAULT_CLIENT
|
|
204
|
+
client: clientId || DEFAULT_CLIENT,
|
|
205
|
+
queryParameters
|
|
183
206
|
});
|
|
184
207
|
return await requestJson({method: 'POST', url: baseUrl, accessToken, body});
|
|
185
208
|
}
|
|
@@ -255,7 +278,8 @@ export async function fetchLayerData({
|
|
|
255
278
|
formatTiles,
|
|
256
279
|
clientId,
|
|
257
280
|
aggregationExp,
|
|
258
|
-
aggregationResLevel
|
|
281
|
+
aggregationResLevel,
|
|
282
|
+
queryParameters
|
|
259
283
|
}: FetchLayerDataParams): Promise<FetchLayerDataResult> {
|
|
260
284
|
// Internally we split data fetching into two parts to allow us to
|
|
261
285
|
// conditionally fetch the actual data, depending on the metadata state
|
|
@@ -270,7 +294,8 @@ export async function fetchLayerData({
|
|
|
270
294
|
formatTiles,
|
|
271
295
|
clientId,
|
|
272
296
|
aggregationExp,
|
|
273
|
-
aggregationResLevel
|
|
297
|
+
aggregationResLevel,
|
|
298
|
+
queryParameters
|
|
274
299
|
});
|
|
275
300
|
|
|
276
301
|
const data = await requestData({url, format: mapFormat, accessToken});
|
|
@@ -289,7 +314,8 @@ async function _fetchDataUrl({
|
|
|
289
314
|
formatTiles,
|
|
290
315
|
clientId,
|
|
291
316
|
aggregationExp,
|
|
292
|
-
aggregationResLevel
|
|
317
|
+
aggregationResLevel,
|
|
318
|
+
queryParameters
|
|
293
319
|
}: FetchLayerDataParams) {
|
|
294
320
|
const defaultCredentials = getDefaultCredentials();
|
|
295
321
|
// Only pick up default credentials if they have been defined for
|
|
@@ -322,7 +348,8 @@ async function _fetchDataUrl({
|
|
|
322
348
|
columns,
|
|
323
349
|
clientId,
|
|
324
350
|
aggregationExp,
|
|
325
|
-
aggregationResLevel
|
|
351
|
+
aggregationResLevel,
|
|
352
|
+
queryParameters
|
|
326
353
|
});
|
|
327
354
|
let url: string | null = null;
|
|
328
355
|
let mapFormat: Format | undefined;
|
|
@@ -361,11 +388,23 @@ async function _fetchMapDataset(
|
|
|
361
388
|
dataset,
|
|
362
389
|
accessToken: string,
|
|
363
390
|
credentials: CloudNativeCredentials,
|
|
364
|
-
clientId?: string
|
|
391
|
+
clientId?: string,
|
|
392
|
+
queryParameters?: QueryParameters
|
|
365
393
|
) {
|
|
366
|
-
const {
|
|
394
|
+
const {
|
|
395
|
+
aggregationExp,
|
|
396
|
+
aggregationResLevel,
|
|
397
|
+
connectionName: connection,
|
|
398
|
+
columns,
|
|
399
|
+
format,
|
|
400
|
+
geoColumn,
|
|
401
|
+
source,
|
|
402
|
+
type
|
|
403
|
+
} = dataset;
|
|
367
404
|
// First fetch metadata
|
|
368
405
|
const {url, mapFormat} = await _fetchDataUrl({
|
|
406
|
+
aggregationExp,
|
|
407
|
+
aggregationResLevel,
|
|
369
408
|
clientId,
|
|
370
409
|
credentials: {...credentials, accessToken},
|
|
371
410
|
connection,
|
|
@@ -373,7 +412,8 @@ async function _fetchMapDataset(
|
|
|
373
412
|
format,
|
|
374
413
|
geoColumn,
|
|
375
414
|
source,
|
|
376
|
-
type
|
|
415
|
+
type,
|
|
416
|
+
queryParameters
|
|
377
417
|
});
|
|
378
418
|
|
|
379
419
|
// Extract the last time the data changed
|
|
@@ -389,6 +429,31 @@ async function _fetchMapDataset(
|
|
|
389
429
|
return true;
|
|
390
430
|
}
|
|
391
431
|
|
|
432
|
+
async function _fetchTilestats(
|
|
433
|
+
attribute,
|
|
434
|
+
dataset,
|
|
435
|
+
accessToken: string,
|
|
436
|
+
credentials: CloudNativeCredentials
|
|
437
|
+
) {
|
|
438
|
+
const {connectionName: connection, source, type} = dataset;
|
|
439
|
+
|
|
440
|
+
const statsUrl = buildStatsUrlFromBase(credentials.apiBaseUrl);
|
|
441
|
+
let url = `${statsUrl}/${connection}/`;
|
|
442
|
+
if (type === MAP_TYPES.QUERY) {
|
|
443
|
+
url += `${attribute}?q=${source}`;
|
|
444
|
+
} else {
|
|
445
|
+
// MAP_TYPE.TABLE
|
|
446
|
+
url += `${source}/${attribute}`;
|
|
447
|
+
}
|
|
448
|
+
const stats = await requestData({url, format: FORMATS.JSON, accessToken});
|
|
449
|
+
|
|
450
|
+
// Replace tilestats for attribute with value from API
|
|
451
|
+
const {attributes} = dataset.data.tilestats.layers[0];
|
|
452
|
+
const index = attributes.findIndex(d => d.attribute === attribute);
|
|
453
|
+
attributes[index] = stats;
|
|
454
|
+
return true;
|
|
455
|
+
}
|
|
456
|
+
|
|
392
457
|
async function fillInMapDatasets(
|
|
393
458
|
{datasets, token},
|
|
394
459
|
clientId: string,
|
|
@@ -398,6 +463,42 @@ async function fillInMapDatasets(
|
|
|
398
463
|
return await Promise.all(promises);
|
|
399
464
|
}
|
|
400
465
|
|
|
466
|
+
async function fillInTileStats(
|
|
467
|
+
{datasets, keplerMapConfig, token},
|
|
468
|
+
credentials: CloudNativeCredentials
|
|
469
|
+
) {
|
|
470
|
+
const attributes: {attribute?: string; dataset?: any}[] = [];
|
|
471
|
+
const {layers} = keplerMapConfig.config.visState;
|
|
472
|
+
for (const layer of layers) {
|
|
473
|
+
for (const channel of Object.keys(layer.visualChannels)) {
|
|
474
|
+
const attribute = layer.visualChannels[channel]?.name;
|
|
475
|
+
if (attribute) {
|
|
476
|
+
const dataset = datasets.find(d => d.id === layer.config.dataId);
|
|
477
|
+
if (dataset.data.tilestats && dataset.type !== MAP_TYPES.TILESET) {
|
|
478
|
+
// Only fetch stats for QUERY & TABLE map types
|
|
479
|
+
attributes.push({attribute, dataset});
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
// Remove duplicates to avoid repeated requests
|
|
485
|
+
const filteredAttributes: {attribute?: string; dataset?: any}[] = [];
|
|
486
|
+
for (const a of attributes) {
|
|
487
|
+
if (
|
|
488
|
+
!filteredAttributes.find(
|
|
489
|
+
({attribute, dataset}) => attribute === a.attribute && dataset === a.dataset
|
|
490
|
+
)
|
|
491
|
+
) {
|
|
492
|
+
filteredAttributes.push(a);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const promises = filteredAttributes.map(({attribute, dataset}) =>
|
|
497
|
+
_fetchTilestats(attribute, dataset, token, credentials)
|
|
498
|
+
);
|
|
499
|
+
return await Promise.all(promises);
|
|
500
|
+
}
|
|
501
|
+
|
|
401
502
|
export async function fetchMap({
|
|
402
503
|
cartoMapId,
|
|
403
504
|
clientId,
|
|
@@ -466,6 +567,9 @@ export async function fetchMap({
|
|
|
466
567
|
|
|
467
568
|
// Mutates map.datasets so that dataset.data contains data
|
|
468
569
|
await fillInMapDatasets(map, clientId, localCreds);
|
|
570
|
+
|
|
571
|
+
// Mutates attributes in visualChannels to contain tile stats
|
|
572
|
+
await fillInTileStats(map, localCreds);
|
|
469
573
|
return {
|
|
470
574
|
...parseMap(map),
|
|
471
575
|
...{stopAutoRefresh}
|
package/src/api/parseMap.ts
CHANGED
|
@@ -176,10 +176,11 @@ function createChannelProps(visualChannels, type, config, data) {
|
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
} else if (colorField) {
|
|
179
|
+
const {colorAggregation: aggregation, colorRange: range} = visConfig;
|
|
179
180
|
result.getFillColor = getColorAccessor(
|
|
180
181
|
colorField,
|
|
181
182
|
colorScale,
|
|
182
|
-
|
|
183
|
+
{aggregation, range},
|
|
183
184
|
visConfig.opacity,
|
|
184
185
|
data
|
|
185
186
|
);
|
|
@@ -189,10 +190,11 @@ function createChannelProps(visualChannels, type, config, data) {
|
|
|
189
190
|
const fallbackOpacity = type === 'point' ? visConfig.opacity : 1;
|
|
190
191
|
const opacity =
|
|
191
192
|
visConfig.strokeOpacity !== undefined ? visConfig.strokeOpacity : fallbackOpacity;
|
|
193
|
+
const {strokeColorAggregation: aggregation, strokeColorRange: range} = visConfig;
|
|
192
194
|
result.getLineColor = getColorAccessor(
|
|
193
195
|
strokeColorField,
|
|
194
196
|
strokeColorScale,
|
|
195
|
-
|
|
197
|
+
{aggregation, range},
|
|
196
198
|
opacity,
|
|
197
199
|
data
|
|
198
200
|
);
|
|
@@ -201,6 +203,7 @@ function createChannelProps(visualChannels, type, config, data) {
|
|
|
201
203
|
result.getElevation = getSizeAccessor(
|
|
202
204
|
heightField,
|
|
203
205
|
heightScale,
|
|
206
|
+
visConfig.heightAggregation,
|
|
204
207
|
visConfig.heightRange || visConfig.sizeRange,
|
|
205
208
|
data
|
|
206
209
|
);
|
|
@@ -209,6 +212,7 @@ function createChannelProps(visualChannels, type, config, data) {
|
|
|
209
212
|
result.getPointRadius = getSizeAccessor(
|
|
210
213
|
sizeField,
|
|
211
214
|
sizeScale,
|
|
215
|
+
visConfig.sizeAggregation,
|
|
212
216
|
visConfig.radiusRange || visConfig.sizeRange,
|
|
213
217
|
data
|
|
214
218
|
);
|
package/src/config.ts
CHANGED
|
@@ -50,11 +50,21 @@ export function getDefaultCredentials(): Credentials {
|
|
|
50
50
|
return credentials;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
export
|
|
54
|
-
|
|
53
|
+
export type V3Endpoint = 'maps' | 'stats';
|
|
54
|
+
|
|
55
|
+
function buildUrlFromBase(apiBaseUrl: string, endpoint: V3Endpoint) {
|
|
56
|
+
let suffix = `/v3/${endpoint}`;
|
|
55
57
|
if (apiBaseUrl.endsWith('/')) {
|
|
56
58
|
suffix = suffix.substring(1);
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
return `${apiBaseUrl}${suffix}`;
|
|
60
62
|
}
|
|
63
|
+
|
|
64
|
+
export function buildMapsUrlFromBase(apiBaseUrl: string): string {
|
|
65
|
+
return buildUrlFromBase(apiBaseUrl, 'maps');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function buildStatsUrlFromBase(apiBaseUrl: string): string {
|
|
69
|
+
return buildUrlFromBase(apiBaseUrl, 'stats');
|
|
70
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CompositeLayer,
|
|
3
|
-
Layer,
|
|
4
|
-
log,
|
|
5
3
|
CompositeLayerProps,
|
|
4
|
+
Layer,
|
|
6
5
|
LayerProps,
|
|
7
|
-
|
|
6
|
+
log,
|
|
7
|
+
UpdateParameters
|
|
8
8
|
} from '@deck.gl/core';
|
|
9
|
-
|
|
10
|
-
import H3TileLayer from './h3-tile-layer';
|
|
11
|
-
import QuadbinTileLayer from './quadbin-tile-layer';
|
|
9
|
+
|
|
12
10
|
import {MVTLayer} from '@deck.gl/geo-layers';
|
|
13
11
|
import {fetchLayerData, getDataV2, API_VERSIONS} from '../api';
|
|
12
|
+
import {layerFromTileDataset} from '../api/layer-map';
|
|
14
13
|
import {
|
|
15
14
|
COLUMNS_SUPPORT,
|
|
16
15
|
FORMATS,
|
|
@@ -18,7 +17,7 @@ import {
|
|
|
18
17
|
MapType,
|
|
19
18
|
MAP_TYPES,
|
|
20
19
|
TileFormat,
|
|
21
|
-
|
|
20
|
+
QueryParameters
|
|
22
21
|
} from '../api/maps-api-common';
|
|
23
22
|
import {
|
|
24
23
|
ClassicCredentials,
|
|
@@ -66,7 +65,10 @@ const defaultProps = {
|
|
|
66
65
|
aggregationExp: null,
|
|
67
66
|
|
|
68
67
|
// (Number, optional): aggregation resolution level. Only used for spatial index datasets, defaults to 6 for quadbins, 4 for h3
|
|
69
|
-
aggregationResLevel: null
|
|
68
|
+
aggregationResLevel: null,
|
|
69
|
+
|
|
70
|
+
// (QueryParameters, optional): query parameters to be sent to the server.
|
|
71
|
+
queryParameters: null
|
|
70
72
|
};
|
|
71
73
|
|
|
72
74
|
/** All properties supported by CartoLayer. */
|
|
@@ -151,6 +153,9 @@ type _CartoLayerProps = {
|
|
|
151
153
|
|
|
152
154
|
/** Aggregation resolution level. Only used for spatial index datasets, defaults to 6 for quadbins, 4 for h3. **/
|
|
153
155
|
aggregationResLevel?: number;
|
|
156
|
+
|
|
157
|
+
/** Query parameters to be sent to the server. **/
|
|
158
|
+
queryParameters?: QueryParameters;
|
|
154
159
|
};
|
|
155
160
|
|
|
156
161
|
export default class CartoLayer<ExtraProps = {}> extends CompositeLayer<
|
|
@@ -209,16 +214,7 @@ export default class CartoLayer<ExtraProps = {}> extends CompositeLayer<
|
|
|
209
214
|
}
|
|
210
215
|
}
|
|
211
216
|
|
|
212
|
-
updateState({
|
|
213
|
-
props,
|
|
214
|
-
oldProps,
|
|
215
|
-
changeFlags
|
|
216
|
-
}: {
|
|
217
|
-
props: CartoLayerProps;
|
|
218
|
-
oldProps: CartoLayerProps;
|
|
219
|
-
context: any;
|
|
220
|
-
changeFlags: ChangeFlags;
|
|
221
|
-
}): void {
|
|
217
|
+
updateState({props, oldProps, changeFlags}: UpdateParameters<this>) {
|
|
222
218
|
this._checkProps(props);
|
|
223
219
|
const shouldUpdateData =
|
|
224
220
|
changeFlags.dataChanged ||
|
|
@@ -229,7 +225,8 @@ export default class CartoLayer<ExtraProps = {}> extends CompositeLayer<
|
|
|
229
225
|
props.formatTiles !== oldProps.formatTiles ||
|
|
230
226
|
props.type !== oldProps.type ||
|
|
231
227
|
JSON.stringify(props.columns) !== JSON.stringify(oldProps.columns) ||
|
|
232
|
-
JSON.stringify(props.credentials) !== JSON.stringify(oldProps.credentials)
|
|
228
|
+
JSON.stringify(props.credentials) !== JSON.stringify(oldProps.credentials) ||
|
|
229
|
+
JSON.stringify(props.queryParameters) !== JSON.stringify(oldProps.queryParameters);
|
|
233
230
|
|
|
234
231
|
if (shouldUpdateData) {
|
|
235
232
|
this.setState({data: null, apiVersion: null});
|
|
@@ -240,7 +237,7 @@ export default class CartoLayer<ExtraProps = {}> extends CompositeLayer<
|
|
|
240
237
|
|
|
241
238
|
async _updateData(): Promise<void> {
|
|
242
239
|
try {
|
|
243
|
-
const {type, data: source,
|
|
240
|
+
const {type, data: source, credentials, connection, ...rest} = this.props;
|
|
244
241
|
const localConfig = {...getDefaultCredentials(), ...credentials};
|
|
245
242
|
const {apiVersion} = localConfig;
|
|
246
243
|
|
|
@@ -253,7 +250,6 @@ export default class CartoLayer<ExtraProps = {}> extends CompositeLayer<
|
|
|
253
250
|
result = await fetchLayerData({
|
|
254
251
|
type,
|
|
255
252
|
source,
|
|
256
|
-
clientId,
|
|
257
253
|
credentials: credentials as CloudNativeCredentials,
|
|
258
254
|
connection,
|
|
259
255
|
...rest,
|
|
@@ -294,19 +290,10 @@ export default class CartoLayer<ExtraProps = {}> extends CompositeLayer<
|
|
|
294
290
|
|
|
295
291
|
/* global URL */
|
|
296
292
|
const tileUrl = new URL(data.tiles[0]);
|
|
297
|
-
|
|
298
293
|
props.formatTiles =
|
|
299
|
-
props.formatTiles ||
|
|
300
|
-
(tileUrl.searchParams.get('formatTiles') as TileFormat) ||
|
|
301
|
-
TILE_FORMATS.MVT;
|
|
294
|
+
props.formatTiles || (tileUrl.searchParams.get('formatTiles') as TileFormat);
|
|
302
295
|
|
|
303
|
-
|
|
304
|
-
return [H3TileLayer, props];
|
|
305
|
-
}
|
|
306
|
-
if (data.scheme === 'quadbin') {
|
|
307
|
-
return [QuadbinTileLayer, props];
|
|
308
|
-
}
|
|
309
|
-
return props.formatTiles === TILE_FORMATS.MVT ? [MVTLayer, props] : [CartoTileLayer, props];
|
|
296
|
+
return [layerFromTileDataset(props.formatTiles, data.scheme), props];
|
|
310
297
|
}
|
|
311
298
|
|
|
312
299
|
renderLayers(): Layer | null {
|