@deck.gl/carto 8.8.4 → 8.8.7
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 +31412 -22945
- 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 +230 -57
- 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 +15 -23
- package/dist/es5/layers/carto-layer.js.map +1 -1
- package/dist/es5/layers/carto-tile-layer.js +1 -1
- package/dist/es5/layers/carto-tile-layer.js.map +1 -1
- package/dist/es5/layers/quadbin-utils.js +2 -0
- package/dist/es5/layers/quadbin-utils.js.map +1 -1
- package/dist/es5/layers/schema/carto-spatial-tile-loader.js +99 -0
- package/dist/es5/layers/schema/carto-spatial-tile-loader.js.map +1 -0
- package/dist/es5/layers/schema/carto-spatial-tile.js +117 -0
- package/dist/es5/layers/schema/carto-spatial-tile.js.map +1 -0
- package/dist/es5/layers/schema/carto-tile.js +5 -1
- package/dist/es5/layers/schema/carto-tile.js.map +1 -1
- package/dist/es5/layers/schema/spatialjson-utils.js +41 -0
- package/dist/es5/layers/schema/spatialjson-utils.js.map +1 -0
- package/dist/es5/layers/spatial-index-tile-layer.js +6 -0
- package/dist/es5/layers/spatial-index-tile-layer.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 +129 -16
- 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 +12 -19
- package/dist/esm/layers/carto-layer.js.map +1 -1
- package/dist/esm/layers/carto-tile-layer.js +1 -1
- package/dist/esm/layers/carto-tile-layer.js.map +1 -1
- package/dist/esm/layers/quadbin-utils.js +2 -5
- package/dist/esm/layers/quadbin-utils.js.map +1 -1
- package/dist/esm/layers/schema/carto-spatial-tile-loader.js +56 -0
- package/dist/esm/layers/schema/carto-spatial-tile-loader.js.map +1 -0
- package/dist/esm/layers/schema/carto-spatial-tile.js +72 -0
- package/dist/esm/layers/schema/carto-spatial-tile.js.map +1 -0
- package/dist/esm/layers/schema/carto-tile.js +2 -2
- package/dist/esm/layers/schema/carto-tile.js.map +1 -1
- package/dist/esm/layers/schema/spatialjson-utils.js +26 -0
- package/dist/esm/layers/schema/spatialjson-utils.js.map +1 -0
- package/dist/esm/layers/spatial-index-tile-layer.js +3 -0
- package/dist/esm/layers/spatial-index-tile-layer.js.map +1 -1
- package/dist.min.js +138 -138
- package/package.json +2 -2
- 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 +148 -21
- 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 +26 -33
- package/src/layers/carto-tile-layer.ts +6 -3
- package/src/layers/quadbin-utils.ts +2 -2
- package/src/layers/schema/carto-spatial-tile-loader.ts +59 -0
- package/src/layers/schema/carto-spatial-tile.ts +83 -0
- package/src/layers/schema/carto-tile.ts +6 -6
- package/src/layers/schema/spatialjson-utils.ts +35 -0
- package/src/layers/spatial-index-tile-layer.ts +4 -0
- 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 +8 -4
- 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 +8 -8
- package/typed/layers/carto-layer.d.ts.map +1 -1
- package/typed/layers/carto-tile-layer.d.ts.map +1 -1
- package/typed/layers/quadbin-utils.d.ts +2 -0
- package/typed/layers/quadbin-utils.d.ts.map +1 -1
- package/typed/layers/schema/carto-spatial-tile-loader.d.ts +4 -0
- package/typed/layers/schema/carto-spatial-tile-loader.d.ts.map +1 -0
- package/typed/layers/schema/carto-spatial-tile.d.ts +21 -0
- package/typed/layers/schema/carto-spatial-tile.d.ts.map +1 -0
- package/typed/layers/schema/carto-tile.d.ts +15 -3
- package/typed/layers/schema/carto-tile.d.ts.map +1 -1
- package/typed/layers/schema/spatialjson-utils.d.ts +25 -0
- package/typed/layers/schema/spatialjson-utils.d.ts.map +1 -0
- package/typed/layers/spatial-index-tile-layer.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.d.ts +0 -21
- package/typed/layers/quadkey-tile-layer.d.ts.map +0 -1
- package/typed/layers/quadkey-tile-layer.js +0 -42
- package/typed/layers/quadkey-tileset-2d.d.ts +0 -15
- package/typed/layers/quadkey-tileset-2d.d.ts.map +0 -1
- 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.7",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
8
8
|
},
|
|
@@ -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": "4485a8be47b76ba5f28447af304c683a00bbb4eb"
|
|
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
|
|
@@ -23,9 +29,11 @@ import {assert} from '../utils';
|
|
|
23
29
|
const MAX_GET_LENGTH = 2048;
|
|
24
30
|
const DEFAULT_CLIENT = 'deck-gl-carto';
|
|
25
31
|
|
|
32
|
+
export type Headers = Record<string, string>;
|
|
26
33
|
interface RequestParams {
|
|
27
34
|
method?: string;
|
|
28
35
|
url: string;
|
|
36
|
+
headers?: Headers;
|
|
29
37
|
accessToken?: string;
|
|
30
38
|
body?: any;
|
|
31
39
|
}
|
|
@@ -33,8 +41,15 @@ interface RequestParams {
|
|
|
33
41
|
/**
|
|
34
42
|
* Request against Maps API
|
|
35
43
|
*/
|
|
36
|
-
async function request({
|
|
37
|
-
|
|
44
|
+
async function request({
|
|
45
|
+
method,
|
|
46
|
+
url,
|
|
47
|
+
headers: customHeaders,
|
|
48
|
+
accessToken,
|
|
49
|
+
body
|
|
50
|
+
}: RequestParams): Promise<Response> {
|
|
51
|
+
const headers: Headers = {
|
|
52
|
+
...customHeaders,
|
|
38
53
|
Accept: 'application/json'
|
|
39
54
|
};
|
|
40
55
|
|
|
@@ -61,10 +76,11 @@ async function request({method, url, accessToken, body}: RequestParams): Promise
|
|
|
61
76
|
async function requestJson<T = unknown>({
|
|
62
77
|
method,
|
|
63
78
|
url,
|
|
79
|
+
headers,
|
|
64
80
|
accessToken,
|
|
65
81
|
body
|
|
66
82
|
}: RequestParams): Promise<T> {
|
|
67
|
-
const response = await request({method, url, accessToken, body});
|
|
83
|
+
const response = await request({method, url, headers, accessToken, body});
|
|
68
84
|
const json = await response.json();
|
|
69
85
|
|
|
70
86
|
if (!response.ok) {
|
|
@@ -115,8 +131,10 @@ type FetchLayerDataParams = {
|
|
|
115
131
|
clientId?: string;
|
|
116
132
|
format?: Format;
|
|
117
133
|
formatTiles?: TileFormat;
|
|
134
|
+
headers?: Headers;
|
|
118
135
|
aggregationExp?: string;
|
|
119
136
|
aggregationResLevel?: number;
|
|
137
|
+
queryParameters?: QueryParameters;
|
|
120
138
|
};
|
|
121
139
|
|
|
122
140
|
/**
|
|
@@ -129,13 +147,18 @@ function getParameters({
|
|
|
129
147
|
columns,
|
|
130
148
|
clientId,
|
|
131
149
|
aggregationExp,
|
|
132
|
-
aggregationResLevel
|
|
150
|
+
aggregationResLevel,
|
|
151
|
+
queryParameters
|
|
133
152
|
}: Omit<FetchLayerDataParams, 'connection' | 'credentials'>) {
|
|
134
153
|
const parameters = [encodeParameter('client', clientId || DEFAULT_CLIENT)];
|
|
135
154
|
|
|
136
155
|
const sourceName = type === MAP_TYPES.QUERY ? 'q' : 'name';
|
|
137
156
|
parameters.push(encodeParameter(sourceName, source));
|
|
138
157
|
|
|
158
|
+
if (queryParameters) {
|
|
159
|
+
parameters.push(encodeParameter('queryParameters', JSON.stringify(queryParameters)));
|
|
160
|
+
}
|
|
161
|
+
|
|
139
162
|
if (geoColumn) {
|
|
140
163
|
parameters.push(encodeParameter('geo_column', geoColumn));
|
|
141
164
|
}
|
|
@@ -144,6 +167,9 @@ function getParameters({
|
|
|
144
167
|
}
|
|
145
168
|
if (aggregationExp) {
|
|
146
169
|
parameters.push(encodeParameter('aggregationExp', aggregationExp));
|
|
170
|
+
} else if (isSpatialIndexGeoColumn(geoColumn)) {
|
|
171
|
+
// Default aggregationExp required for spatial index layers
|
|
172
|
+
parameters.push(encodeParameter('aggregationExp', '1 AS value'));
|
|
147
173
|
}
|
|
148
174
|
if (aggregationResLevel) {
|
|
149
175
|
parameters.push(encodeParameter('aggregationResLevel', aggregationResLevel));
|
|
@@ -152,6 +178,11 @@ function getParameters({
|
|
|
152
178
|
return parameters.join('&');
|
|
153
179
|
}
|
|
154
180
|
|
|
181
|
+
function isSpatialIndexGeoColumn(geoColumn: string | undefined) {
|
|
182
|
+
const spatialIndex = geoColumn?.split(':')[0];
|
|
183
|
+
return spatialIndex === 'h3' || spatialIndex === 'quadbin';
|
|
184
|
+
}
|
|
185
|
+
|
|
155
186
|
export async function mapInstantiation({
|
|
156
187
|
type,
|
|
157
188
|
source,
|
|
@@ -160,8 +191,10 @@ export async function mapInstantiation({
|
|
|
160
191
|
geoColumn,
|
|
161
192
|
columns,
|
|
162
193
|
clientId,
|
|
194
|
+
headers,
|
|
163
195
|
aggregationExp,
|
|
164
|
-
aggregationResLevel
|
|
196
|
+
aggregationResLevel,
|
|
197
|
+
queryParameters
|
|
165
198
|
}: FetchLayerDataParams): Promise<MapInstantiation> {
|
|
166
199
|
const baseUrl = `${credentials.mapsUrl}/${connection}/${type}`;
|
|
167
200
|
const url = `${baseUrl}?${getParameters({
|
|
@@ -170,8 +203,9 @@ export async function mapInstantiation({
|
|
|
170
203
|
geoColumn,
|
|
171
204
|
columns,
|
|
172
205
|
clientId,
|
|
206
|
+
aggregationResLevel,
|
|
173
207
|
aggregationExp,
|
|
174
|
-
|
|
208
|
+
queryParameters
|
|
175
209
|
})}`;
|
|
176
210
|
const {accessToken} = credentials;
|
|
177
211
|
|
|
@@ -179,12 +213,13 @@ export async function mapInstantiation({
|
|
|
179
213
|
// need to be a POST request
|
|
180
214
|
const body = JSON.stringify({
|
|
181
215
|
q: source,
|
|
182
|
-
client: clientId || DEFAULT_CLIENT
|
|
216
|
+
client: clientId || DEFAULT_CLIENT,
|
|
217
|
+
queryParameters
|
|
183
218
|
});
|
|
184
|
-
return await requestJson({method: 'POST', url: baseUrl, accessToken, body});
|
|
219
|
+
return await requestJson({method: 'POST', url: baseUrl, headers, accessToken, body});
|
|
185
220
|
}
|
|
186
221
|
|
|
187
|
-
return await requestJson({url, accessToken});
|
|
222
|
+
return await requestJson({url, headers, accessToken});
|
|
188
223
|
}
|
|
189
224
|
|
|
190
225
|
function getUrlFromMetadata(metadata: MapInstantiation, format: Format): string | null {
|
|
@@ -254,8 +289,10 @@ export async function fetchLayerData({
|
|
|
254
289
|
format,
|
|
255
290
|
formatTiles,
|
|
256
291
|
clientId,
|
|
292
|
+
headers,
|
|
257
293
|
aggregationExp,
|
|
258
|
-
aggregationResLevel
|
|
294
|
+
aggregationResLevel,
|
|
295
|
+
queryParameters
|
|
259
296
|
}: FetchLayerDataParams): Promise<FetchLayerDataResult> {
|
|
260
297
|
// Internally we split data fetching into two parts to allow us to
|
|
261
298
|
// conditionally fetch the actual data, depending on the metadata state
|
|
@@ -269,8 +306,10 @@ export async function fetchLayerData({
|
|
|
269
306
|
format,
|
|
270
307
|
formatTiles,
|
|
271
308
|
clientId,
|
|
309
|
+
headers,
|
|
272
310
|
aggregationExp,
|
|
273
|
-
aggregationResLevel
|
|
311
|
+
aggregationResLevel,
|
|
312
|
+
queryParameters
|
|
274
313
|
});
|
|
275
314
|
|
|
276
315
|
const data = await requestData({url, format: mapFormat, accessToken});
|
|
@@ -288,8 +327,10 @@ async function _fetchDataUrl({
|
|
|
288
327
|
format,
|
|
289
328
|
formatTiles,
|
|
290
329
|
clientId,
|
|
330
|
+
headers,
|
|
291
331
|
aggregationExp,
|
|
292
|
-
aggregationResLevel
|
|
332
|
+
aggregationResLevel,
|
|
333
|
+
queryParameters
|
|
293
334
|
}: FetchLayerDataParams) {
|
|
294
335
|
const defaultCredentials = getDefaultCredentials();
|
|
295
336
|
// Only pick up default credentials if they have been defined for
|
|
@@ -321,8 +362,10 @@ async function _fetchDataUrl({
|
|
|
321
362
|
geoColumn,
|
|
322
363
|
columns,
|
|
323
364
|
clientId,
|
|
365
|
+
headers,
|
|
324
366
|
aggregationExp,
|
|
325
|
-
aggregationResLevel
|
|
367
|
+
aggregationResLevel,
|
|
368
|
+
queryParameters
|
|
326
369
|
});
|
|
327
370
|
let url: string | null = null;
|
|
328
371
|
let mapFormat: Format | undefined;
|
|
@@ -361,19 +404,34 @@ async function _fetchMapDataset(
|
|
|
361
404
|
dataset,
|
|
362
405
|
accessToken: string,
|
|
363
406
|
credentials: CloudNativeCredentials,
|
|
364
|
-
clientId?: string
|
|
407
|
+
clientId?: string,
|
|
408
|
+
headers?: Headers,
|
|
409
|
+
queryParameters?: QueryParameters
|
|
365
410
|
) {
|
|
366
|
-
const {
|
|
411
|
+
const {
|
|
412
|
+
aggregationExp,
|
|
413
|
+
aggregationResLevel,
|
|
414
|
+
connectionName: connection,
|
|
415
|
+
columns,
|
|
416
|
+
format,
|
|
417
|
+
geoColumn,
|
|
418
|
+
source,
|
|
419
|
+
type
|
|
420
|
+
} = dataset;
|
|
367
421
|
// First fetch metadata
|
|
368
422
|
const {url, mapFormat} = await _fetchDataUrl({
|
|
423
|
+
aggregationExp,
|
|
424
|
+
aggregationResLevel,
|
|
369
425
|
clientId,
|
|
370
426
|
credentials: {...credentials, accessToken},
|
|
371
427
|
connection,
|
|
372
428
|
columns,
|
|
373
429
|
format,
|
|
374
430
|
geoColumn,
|
|
431
|
+
headers,
|
|
375
432
|
source,
|
|
376
|
-
type
|
|
433
|
+
type,
|
|
434
|
+
queryParameters
|
|
377
435
|
});
|
|
378
436
|
|
|
379
437
|
// Extract the last time the data changed
|
|
@@ -389,12 +447,76 @@ async function _fetchMapDataset(
|
|
|
389
447
|
return true;
|
|
390
448
|
}
|
|
391
449
|
|
|
450
|
+
async function _fetchTilestats(
|
|
451
|
+
attribute,
|
|
452
|
+
dataset,
|
|
453
|
+
accessToken: string,
|
|
454
|
+
credentials: CloudNativeCredentials
|
|
455
|
+
) {
|
|
456
|
+
const {connectionName: connection, source, type} = dataset;
|
|
457
|
+
|
|
458
|
+
const statsUrl = buildStatsUrlFromBase(credentials.apiBaseUrl);
|
|
459
|
+
let url = `${statsUrl}/${connection}/`;
|
|
460
|
+
if (type === MAP_TYPES.QUERY) {
|
|
461
|
+
url += `${attribute}?q=${source}`;
|
|
462
|
+
} else {
|
|
463
|
+
// MAP_TYPE.TABLE
|
|
464
|
+
url += `${source}/${attribute}`;
|
|
465
|
+
}
|
|
466
|
+
const stats = await requestData({url, format: FORMATS.JSON, accessToken});
|
|
467
|
+
|
|
468
|
+
// Replace tilestats for attribute with value from API
|
|
469
|
+
const {attributes} = dataset.data.tilestats.layers[0];
|
|
470
|
+
const index = attributes.findIndex(d => d.attribute === attribute);
|
|
471
|
+
attributes[index] = stats;
|
|
472
|
+
return true;
|
|
473
|
+
}
|
|
474
|
+
|
|
392
475
|
async function fillInMapDatasets(
|
|
393
476
|
{datasets, token},
|
|
394
477
|
clientId: string,
|
|
478
|
+
credentials: CloudNativeCredentials,
|
|
479
|
+
headers?: Headers
|
|
480
|
+
) {
|
|
481
|
+
const promises = datasets.map(dataset =>
|
|
482
|
+
_fetchMapDataset(dataset, token, credentials, clientId, headers)
|
|
483
|
+
);
|
|
484
|
+
return await Promise.all(promises);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
async function fillInTileStats(
|
|
488
|
+
{datasets, keplerMapConfig, token},
|
|
395
489
|
credentials: CloudNativeCredentials
|
|
396
490
|
) {
|
|
397
|
-
const
|
|
491
|
+
const attributes: {attribute?: string; dataset?: any}[] = [];
|
|
492
|
+
const {layers} = keplerMapConfig.config.visState;
|
|
493
|
+
for (const layer of layers) {
|
|
494
|
+
for (const channel of Object.keys(layer.visualChannels)) {
|
|
495
|
+
const attribute = layer.visualChannels[channel]?.name;
|
|
496
|
+
if (attribute) {
|
|
497
|
+
const dataset = datasets.find(d => d.id === layer.config.dataId);
|
|
498
|
+
if (dataset.data.tilestats && dataset.type !== MAP_TYPES.TILESET) {
|
|
499
|
+
// Only fetch stats for QUERY & TABLE map types
|
|
500
|
+
attributes.push({attribute, dataset});
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
// Remove duplicates to avoid repeated requests
|
|
506
|
+
const filteredAttributes: {attribute?: string; dataset?: any}[] = [];
|
|
507
|
+
for (const a of attributes) {
|
|
508
|
+
if (
|
|
509
|
+
!filteredAttributes.find(
|
|
510
|
+
({attribute, dataset}) => attribute === a.attribute && dataset === a.dataset
|
|
511
|
+
)
|
|
512
|
+
) {
|
|
513
|
+
filteredAttributes.push(a);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
const promises = filteredAttributes.map(({attribute, dataset}) =>
|
|
518
|
+
_fetchTilestats(attribute, dataset, token, credentials)
|
|
519
|
+
);
|
|
398
520
|
return await Promise.all(promises);
|
|
399
521
|
}
|
|
400
522
|
|
|
@@ -402,12 +524,14 @@ export async function fetchMap({
|
|
|
402
524
|
cartoMapId,
|
|
403
525
|
clientId,
|
|
404
526
|
credentials,
|
|
527
|
+
headers,
|
|
405
528
|
autoRefresh,
|
|
406
529
|
onNewData
|
|
407
530
|
}: {
|
|
408
531
|
cartoMapId: string;
|
|
409
532
|
clientId: string;
|
|
410
533
|
credentials?: CloudNativeCredentials;
|
|
534
|
+
headers?: Headers;
|
|
411
535
|
autoRefresh?: number;
|
|
412
536
|
onNewData?: (map: any) => void;
|
|
413
537
|
}) {
|
|
@@ -436,7 +560,7 @@ export async function fetchMap({
|
|
|
436
560
|
}
|
|
437
561
|
|
|
438
562
|
const url = `${localCreds.mapsUrl}/public/${cartoMapId}`;
|
|
439
|
-
const map = await requestJson<any>({url, accessToken});
|
|
563
|
+
const map = await requestJson<any>({url, headers, accessToken});
|
|
440
564
|
|
|
441
565
|
// Periodically check if the data has changed. Note that this
|
|
442
566
|
// will not update when a map is published.
|
|
@@ -444,7 +568,7 @@ export async function fetchMap({
|
|
|
444
568
|
if (autoRefresh) {
|
|
445
569
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
446
570
|
const intervalId = setInterval(async () => {
|
|
447
|
-
const changed = await fillInMapDatasets(map, clientId, localCreds);
|
|
571
|
+
const changed = await fillInMapDatasets(map, clientId, localCreds, headers);
|
|
448
572
|
if (onNewData && changed.some(v => v === true)) {
|
|
449
573
|
onNewData(parseMap(map));
|
|
450
574
|
}
|
|
@@ -465,7 +589,10 @@ export async function fetchMap({
|
|
|
465
589
|
});
|
|
466
590
|
|
|
467
591
|
// Mutates map.datasets so that dataset.data contains data
|
|
468
|
-
await fillInMapDatasets(map, clientId, localCreds);
|
|
592
|
+
await fillInMapDatasets(map, clientId, localCreds, headers);
|
|
593
|
+
|
|
594
|
+
// Mutates attributes in visualChannels to contain tile stats
|
|
595
|
+
await fillInTileStats(map, localCreds);
|
|
469
596
|
return {
|
|
470
597
|
...parseMap(map),
|
|
471
598
|
...{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