@deck.gl/carto 8.8.2 → 8.8.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 +298 -82
- package/dist/es5/api/layer-map.js +104 -17
- package/dist/es5/api/layer-map.js.map +1 -1
- package/dist/es5/api/maps-v3-client.js +191 -35
- 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/layers/carto-layer.js +4 -17
- 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/layer-map.js +79 -14
- package/dist/esm/api/layer-map.js.map +1 -1
- package/dist/esm/api/maps-v3-client.js +90 -3
- 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/layers/carto-layer.js +4 -15
- 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/layer-map.ts +76 -13
- package/src/api/maps-v3-client.ts +92 -4
- package/src/api/parseMap.ts +6 -2
- package/src/config.ts +12 -2
- package/src/layers/carto-layer.ts +9 -29
- 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/layer-map.d.ts +12 -4
- package/typed/api/layer-map.d.ts.map +1 -1
- 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/layers/carto-layer.d.ts +2 -7
- 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/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.5",
|
|
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": "96af77adfd71563e0da68acd4e7ae318f551c5de"
|
|
65
65
|
}
|
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
|
}
|
|
@@ -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,
|
|
@@ -144,6 +149,9 @@ function getParameters({
|
|
|
144
149
|
}
|
|
145
150
|
if (aggregationExp) {
|
|
146
151
|
parameters.push(encodeParameter('aggregationExp', aggregationExp));
|
|
152
|
+
} else if (isSpatialIndexGeoColumn(geoColumn)) {
|
|
153
|
+
// Default aggregationExp required for spatial index layers
|
|
154
|
+
parameters.push(encodeParameter('aggregationExp', '1 AS value'));
|
|
147
155
|
}
|
|
148
156
|
if (aggregationResLevel) {
|
|
149
157
|
parameters.push(encodeParameter('aggregationResLevel', aggregationResLevel));
|
|
@@ -152,6 +160,11 @@ function getParameters({
|
|
|
152
160
|
return parameters.join('&');
|
|
153
161
|
}
|
|
154
162
|
|
|
163
|
+
function isSpatialIndexGeoColumn(geoColumn: string | undefined) {
|
|
164
|
+
const spatialIndex = geoColumn?.split(':')[0];
|
|
165
|
+
return spatialIndex === 'h3' || spatialIndex === 'quadbin';
|
|
166
|
+
}
|
|
167
|
+
|
|
155
168
|
export async function mapInstantiation({
|
|
156
169
|
type,
|
|
157
170
|
source,
|
|
@@ -170,8 +183,8 @@ export async function mapInstantiation({
|
|
|
170
183
|
geoColumn,
|
|
171
184
|
columns,
|
|
172
185
|
clientId,
|
|
173
|
-
|
|
174
|
-
|
|
186
|
+
aggregationResLevel,
|
|
187
|
+
aggregationExp
|
|
175
188
|
})}`;
|
|
176
189
|
const {accessToken} = credentials;
|
|
177
190
|
|
|
@@ -363,9 +376,20 @@ async function _fetchMapDataset(
|
|
|
363
376
|
credentials: CloudNativeCredentials,
|
|
364
377
|
clientId?: string
|
|
365
378
|
) {
|
|
366
|
-
const {
|
|
379
|
+
const {
|
|
380
|
+
aggregationExp,
|
|
381
|
+
aggregationResLevel,
|
|
382
|
+
connectionName: connection,
|
|
383
|
+
columns,
|
|
384
|
+
format,
|
|
385
|
+
geoColumn,
|
|
386
|
+
source,
|
|
387
|
+
type
|
|
388
|
+
} = dataset;
|
|
367
389
|
// First fetch metadata
|
|
368
390
|
const {url, mapFormat} = await _fetchDataUrl({
|
|
391
|
+
aggregationExp,
|
|
392
|
+
aggregationResLevel,
|
|
369
393
|
clientId,
|
|
370
394
|
credentials: {...credentials, accessToken},
|
|
371
395
|
connection,
|
|
@@ -389,6 +413,31 @@ async function _fetchMapDataset(
|
|
|
389
413
|
return true;
|
|
390
414
|
}
|
|
391
415
|
|
|
416
|
+
async function _fetchTilestats(
|
|
417
|
+
attribute,
|
|
418
|
+
dataset,
|
|
419
|
+
accessToken: string,
|
|
420
|
+
credentials: CloudNativeCredentials
|
|
421
|
+
) {
|
|
422
|
+
const {connectionName: connection, source, type} = dataset;
|
|
423
|
+
|
|
424
|
+
const statsUrl = buildStatsUrlFromBase(credentials.apiBaseUrl);
|
|
425
|
+
let url = `${statsUrl}/${connection}/`;
|
|
426
|
+
if (type === MAP_TYPES.QUERY) {
|
|
427
|
+
url += `${attribute}?q=${source}`;
|
|
428
|
+
} else {
|
|
429
|
+
// MAP_TYPE.TABLE
|
|
430
|
+
url += `${source}/${attribute}`;
|
|
431
|
+
}
|
|
432
|
+
const stats = await requestData({url, format: FORMATS.JSON, accessToken});
|
|
433
|
+
|
|
434
|
+
// Replace tilestats for attribute with value from API
|
|
435
|
+
const {attributes} = dataset.data.tilestats.layers[0];
|
|
436
|
+
const index = attributes.findIndex(d => d.attribute === attribute);
|
|
437
|
+
attributes[index] = stats;
|
|
438
|
+
return true;
|
|
439
|
+
}
|
|
440
|
+
|
|
392
441
|
async function fillInMapDatasets(
|
|
393
442
|
{datasets, token},
|
|
394
443
|
clientId: string,
|
|
@@ -398,6 +447,42 @@ async function fillInMapDatasets(
|
|
|
398
447
|
return await Promise.all(promises);
|
|
399
448
|
}
|
|
400
449
|
|
|
450
|
+
async function fillInTileStats(
|
|
451
|
+
{datasets, keplerMapConfig, token},
|
|
452
|
+
credentials: CloudNativeCredentials
|
|
453
|
+
) {
|
|
454
|
+
const attributes: {attribute?: string; dataset?: any}[] = [];
|
|
455
|
+
const {layers} = keplerMapConfig.config.visState;
|
|
456
|
+
for (const layer of layers) {
|
|
457
|
+
for (const channel of Object.keys(layer.visualChannels)) {
|
|
458
|
+
const attribute = layer.visualChannels[channel]?.name;
|
|
459
|
+
if (attribute) {
|
|
460
|
+
const dataset = datasets.find(d => d.id === layer.config.dataId);
|
|
461
|
+
if (dataset.data.tilestats && dataset.type !== MAP_TYPES.TILESET) {
|
|
462
|
+
// Only fetch stats for QUERY & TABLE map types
|
|
463
|
+
attributes.push({attribute, dataset});
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
// Remove duplicates to avoid repeated requests
|
|
469
|
+
const filteredAttributes: {attribute?: string; dataset?: any}[] = [];
|
|
470
|
+
for (const a of attributes) {
|
|
471
|
+
if (
|
|
472
|
+
!filteredAttributes.find(
|
|
473
|
+
({attribute, dataset}) => attribute === a.attribute && dataset === a.dataset
|
|
474
|
+
)
|
|
475
|
+
) {
|
|
476
|
+
filteredAttributes.push(a);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
const promises = filteredAttributes.map(({attribute, dataset}) =>
|
|
481
|
+
_fetchTilestats(attribute, dataset, token, credentials)
|
|
482
|
+
);
|
|
483
|
+
return await Promise.all(promises);
|
|
484
|
+
}
|
|
485
|
+
|
|
401
486
|
export async function fetchMap({
|
|
402
487
|
cartoMapId,
|
|
403
488
|
clientId,
|
|
@@ -466,6 +551,9 @@ export async function fetchMap({
|
|
|
466
551
|
|
|
467
552
|
// Mutates map.datasets so that dataset.data contains data
|
|
468
553
|
await fillInMapDatasets(map, clientId, localCreds);
|
|
554
|
+
|
|
555
|
+
// Mutates attributes in visualChannels to contain tile stats
|
|
556
|
+
await fillInTileStats(map, localCreds);
|
|
469
557
|
return {
|
|
470
558
|
...parseMap(map),
|
|
471
559
|
...{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
|
+
}
|
|
@@ -1,24 +1,22 @@
|
|
|
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,
|
|
17
16
|
GEO_COLUMN_SUPPORT,
|
|
18
17
|
MapType,
|
|
19
18
|
MAP_TYPES,
|
|
20
|
-
TileFormat
|
|
21
|
-
TILE_FORMATS
|
|
19
|
+
TileFormat
|
|
22
20
|
} from '../api/maps-api-common';
|
|
23
21
|
import {
|
|
24
22
|
ClassicCredentials,
|
|
@@ -209,16 +207,7 @@ export default class CartoLayer<ExtraProps = {}> extends CompositeLayer<
|
|
|
209
207
|
}
|
|
210
208
|
}
|
|
211
209
|
|
|
212
|
-
updateState({
|
|
213
|
-
props,
|
|
214
|
-
oldProps,
|
|
215
|
-
changeFlags
|
|
216
|
-
}: {
|
|
217
|
-
props: CartoLayerProps;
|
|
218
|
-
oldProps: CartoLayerProps;
|
|
219
|
-
context: any;
|
|
220
|
-
changeFlags: ChangeFlags;
|
|
221
|
-
}): void {
|
|
210
|
+
updateState({props, oldProps, changeFlags}: UpdateParameters<this>) {
|
|
222
211
|
this._checkProps(props);
|
|
223
212
|
const shouldUpdateData =
|
|
224
213
|
changeFlags.dataChanged ||
|
|
@@ -294,19 +283,10 @@ export default class CartoLayer<ExtraProps = {}> extends CompositeLayer<
|
|
|
294
283
|
|
|
295
284
|
/* global URL */
|
|
296
285
|
const tileUrl = new URL(data.tiles[0]);
|
|
297
|
-
|
|
298
286
|
props.formatTiles =
|
|
299
|
-
props.formatTiles ||
|
|
300
|
-
(tileUrl.searchParams.get('formatTiles') as TileFormat) ||
|
|
301
|
-
TILE_FORMATS.MVT;
|
|
287
|
+
props.formatTiles || (tileUrl.searchParams.get('formatTiles') as TileFormat);
|
|
302
288
|
|
|
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];
|
|
289
|
+
return [layerFromTileDataset(props.formatTiles, data.scheme), props];
|
|
310
290
|
}
|
|
311
291
|
|
|
312
292
|
renderLayers(): Layer | null {
|
|
@@ -1,18 +1,40 @@
|
|
|
1
1
|
import {scaleThreshold} from 'd3-scale';
|
|
2
|
+
import {AccessorFunction} from '@deck.gl/core';
|
|
3
|
+
import {Feature} from 'geojson';
|
|
2
4
|
import getPalette, {Color, DEFAULT_PALETTE, NULL_COLOR} from './palette';
|
|
3
5
|
import {assert, AttributeSelector, getAttrValue} from './utils';
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Helper function for quickly creating a color bins style based on `d3` `scaleThreshold`.
|
|
9
|
+
*
|
|
10
|
+
* Data values of each attribute are rounded down to the nearest value in the domain and are then
|
|
11
|
+
* styled with the corresponding color.
|
|
12
|
+
*
|
|
13
|
+
* @return accessor that maps objects to `Color` values
|
|
14
|
+
*/
|
|
15
|
+
export default function colorBins<DataT = Feature>({
|
|
6
16
|
attr,
|
|
7
17
|
domain,
|
|
8
18
|
colors = DEFAULT_PALETTE,
|
|
9
19
|
nullColor = NULL_COLOR
|
|
10
20
|
}: {
|
|
11
|
-
|
|
21
|
+
/** Attribute or column to symbolize by. */
|
|
22
|
+
attr: AttributeSelector<DataT, number>;
|
|
23
|
+
|
|
24
|
+
/** Category list. Must be a valid list of categories. */
|
|
12
25
|
domain: number[];
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Color assigned to each domain value.
|
|
29
|
+
*
|
|
30
|
+
* Either Array of colors in RGBA or valid named CARTOColors palette.
|
|
31
|
+
* @default `PurpOr`
|
|
32
|
+
*/
|
|
13
33
|
colors?: string | Color[];
|
|
34
|
+
|
|
35
|
+
/** Color for null values. @default: [204, 204, 204] */
|
|
14
36
|
nullColor?: Color;
|
|
15
|
-
}):
|
|
37
|
+
}): AccessorFunction<DataT, Color> {
|
|
16
38
|
assert(Array.isArray(domain), 'Expected "domain" to be an array of numbers');
|
|
17
39
|
|
|
18
40
|
const palette = typeof colors === 'string' ? getPalette(colors, domain.length + 1) : colors;
|
|
@@ -1,19 +1,43 @@
|
|
|
1
|
+
import {AccessorFunction} from '@deck.gl/core';
|
|
2
|
+
import {Feature} from 'geojson';
|
|
1
3
|
import getPalette, {Color, DEFAULT_PALETTE, NULL_COLOR, OTHERS_COLOR} from './palette';
|
|
2
4
|
import {assert, AttributeSelector, getAttrValue} from './utils';
|
|
3
5
|
|
|
4
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Helper function for quickly creating a color category style.
|
|
8
|
+
*
|
|
9
|
+
* Data values of each attribute listed in the domain are mapped one to one
|
|
10
|
+
* with corresponding colors in the range.
|
|
11
|
+
*
|
|
12
|
+
* @return accessor that maps objects to `Color` values
|
|
13
|
+
*/
|
|
14
|
+
export default function colorCategories<DataT = Feature>({
|
|
5
15
|
attr,
|
|
6
16
|
domain,
|
|
7
17
|
colors = DEFAULT_PALETTE,
|
|
8
18
|
nullColor = NULL_COLOR,
|
|
9
19
|
othersColor = OTHERS_COLOR
|
|
10
20
|
}: {
|
|
11
|
-
|
|
12
|
-
|
|
21
|
+
/** Attribute or column to symbolize by */
|
|
22
|
+
attr: string | AttributeSelector<DataT, number | string>;
|
|
23
|
+
|
|
24
|
+
/** Category list. Must be a valid list of categories. */
|
|
25
|
+
domain: number[] | string[];
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Color assigned to each domain value.
|
|
29
|
+
*
|
|
30
|
+
* Either Array of colors in RGBA or valid named CARTOColors palette.
|
|
31
|
+
* @default `PurpOr`
|
|
32
|
+
*/
|
|
13
33
|
colors: string | Color[];
|
|
34
|
+
|
|
35
|
+
/** Color for null values. @default: [204, 204, 204] */
|
|
14
36
|
nullColor?: Color;
|
|
37
|
+
|
|
38
|
+
/** Fallback color for a category not correctly assigned. @default: [119, 119, 119] */
|
|
15
39
|
othersColor?: Color;
|
|
16
|
-
}):
|
|
40
|
+
}): AccessorFunction<DataT, Color> {
|
|
17
41
|
assert(Array.isArray(domain), 'Expected "domain" to be an array of numbers or strings');
|
|
18
42
|
|
|
19
43
|
const colorsByCategory = {};
|
|
@@ -1,18 +1,40 @@
|
|
|
1
|
+
import {AccessorFunction} from '@deck.gl/core';
|
|
1
2
|
import {scaleLinear} from 'd3-scale';
|
|
3
|
+
import {Feature} from 'geojson';
|
|
2
4
|
import getPalette, {Color, DEFAULT_PALETTE, NULL_COLOR} from './palette';
|
|
3
5
|
import {assert, AttributeSelector, getAttrValue} from './utils';
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Helper function for quickly creating a color continuous style.
|
|
9
|
+
*
|
|
10
|
+
* Data values of each field are interpolated linearly across values in the domain and
|
|
11
|
+
* are then styled with a blend of the corresponding color in the range.
|
|
12
|
+
*
|
|
13
|
+
* @return accessor that maps objects to `Color` values
|
|
14
|
+
*/
|
|
15
|
+
export default function colorContinuous<DataT = Feature>({
|
|
6
16
|
attr,
|
|
7
17
|
domain,
|
|
8
18
|
colors = DEFAULT_PALETTE,
|
|
9
19
|
nullColor = NULL_COLOR
|
|
10
20
|
}: {
|
|
11
|
-
|
|
21
|
+
/** Attribute or column to symbolize by. */
|
|
22
|
+
attr: AttributeSelector<DataT, number>;
|
|
23
|
+
|
|
24
|
+
/** Attribute domain to define the data range. */
|
|
12
25
|
domain: number[];
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Color assigned to each domain value.
|
|
29
|
+
*
|
|
30
|
+
* Either Array of colors in RGBA or valid named CARTOColors palette.
|
|
31
|
+
* @default `PurpOr`
|
|
32
|
+
*/
|
|
13
33
|
colors?: string | Color[];
|
|
34
|
+
|
|
35
|
+
/** Color for null values. @default: [204, 204, 204]*/
|
|
14
36
|
nullColor?: Color;
|
|
15
|
-
}):
|
|
37
|
+
}): AccessorFunction<DataT, Color> {
|
|
16
38
|
assert(Array.isArray(domain), 'Expected "domain" to be an array of numbers');
|
|
17
39
|
|
|
18
40
|
const palette = typeof colors === 'string' ? getPalette(colors, domain.length) : colors;
|
package/src/style/utils.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
import {Feature} from 'geojson';
|
|
2
|
+
|
|
1
3
|
const ALLOWED_ATTR_TYPES = Object.freeze(['function', 'string']);
|
|
2
4
|
|
|
3
|
-
type
|
|
4
|
-
export type AttributeSelector = string | ((d: Row) => unknown);
|
|
5
|
+
export type AttributeSelector<DataT = Feature, OutT = any> = string | ((d: DataT) => OutT);
|
|
5
6
|
|
|
6
|
-
export function getAttrValue
|
|
7
|
+
export function getAttrValue<DataT = Feature, OutT = any>(
|
|
8
|
+
attr: string | AttributeSelector<DataT, OutT>,
|
|
9
|
+
d: DataT
|
|
10
|
+
): OutT {
|
|
7
11
|
assert(typeof d === 'object', 'Expected "data" to be an object');
|
|
8
12
|
assert(ALLOWED_ATTR_TYPES.includes(typeof attr), 'Expected "attr" to be a function or string');
|
|
9
13
|
|
|
@@ -11,7 +15,7 @@ export function getAttrValue(attr: AttributeSelector, d: Row): unknown {
|
|
|
11
15
|
if (typeof attr === 'function') {
|
|
12
16
|
return attr(d);
|
|
13
17
|
}
|
|
14
|
-
return d
|
|
18
|
+
return (d as unknown as Feature)?.properties?.[attr] as OutT;
|
|
15
19
|
}
|
|
16
20
|
|
|
17
21
|
export function assert(condition, message = ''): asserts condition {
|