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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/dist.dev.js +33261 -40106
  2. package/dist/es5/api/layer-map.js +60 -21
  3. package/dist/es5/api/layer-map.js.map +1 -1
  4. package/dist/es5/api/maps-api-common.js +1 -0
  5. package/dist/es5/api/maps-api-common.js.map +1 -1
  6. package/dist/es5/api/maps-v3-client.js +56 -31
  7. package/dist/es5/api/maps-v3-client.js.map +1 -1
  8. package/dist/es5/api/parseMap.js +14 -3
  9. package/dist/es5/api/parseMap.js.map +1 -1
  10. package/dist/es5/index.js +16 -0
  11. package/dist/es5/index.js.map +1 -1
  12. package/dist/es5/layers/carto-layer.js +35 -12
  13. package/dist/es5/layers/carto-layer.js.map +1 -1
  14. package/dist/es5/layers/h3-tile-layer.js +96 -0
  15. package/dist/es5/layers/h3-tile-layer.js.map +1 -0
  16. package/dist/es5/layers/h3-tileset-2d.js +165 -0
  17. package/dist/es5/layers/h3-tileset-2d.js.map +1 -0
  18. package/dist/es5/layers/quadkey-tile-layer.js +97 -0
  19. package/dist/es5/layers/quadkey-tile-layer.js.map +1 -0
  20. package/dist/es5/layers/quadkey-tileset-2d.js +89 -0
  21. package/dist/es5/layers/quadkey-tileset-2d.js.map +1 -0
  22. package/dist/esm/api/layer-map.js +39 -10
  23. package/dist/esm/api/layer-map.js.map +1 -1
  24. package/dist/esm/api/maps-api-common.js +1 -0
  25. package/dist/esm/api/maps-api-common.js.map +1 -1
  26. package/dist/esm/api/maps-v3-client.js +58 -30
  27. package/dist/esm/api/maps-v3-client.js.map +1 -1
  28. package/dist/esm/api/parseMap.js +15 -4
  29. package/dist/esm/api/parseMap.js.map +1 -1
  30. package/dist/esm/index.js +2 -0
  31. package/dist/esm/index.js.map +1 -1
  32. package/dist/esm/layers/carto-layer.js +34 -7
  33. package/dist/esm/layers/carto-layer.js.map +1 -1
  34. package/dist/esm/layers/h3-tile-layer.js +61 -0
  35. package/dist/esm/layers/h3-tile-layer.js.map +1 -0
  36. package/dist/esm/layers/h3-tileset-2d.js +103 -0
  37. package/dist/esm/layers/h3-tileset-2d.js.map +1 -0
  38. package/dist/esm/layers/quadkey-tile-layer.js +61 -0
  39. package/dist/esm/layers/quadkey-tile-layer.js.map +1 -0
  40. package/dist/esm/layers/quadkey-tileset-2d.js +48 -0
  41. package/dist/esm/layers/quadkey-tileset-2d.js.map +1 -0
  42. package/dist.min.js +14 -14
  43. package/package.json +9 -8
  44. package/src/api/layer-map.ts +46 -10
  45. package/src/api/maps-api-common.ts +4 -3
  46. package/src/api/maps-v3-client.ts +78 -29
  47. package/src/api/parseMap.ts +20 -5
  48. package/src/index.ts +4 -0
  49. package/src/layers/{carto-layer.js → carto-layer.ts} +155 -22
  50. package/src/layers/h3-tile-layer.js +44 -0
  51. package/src/layers/h3-tileset-2d.js +82 -0
  52. package/src/layers/quadkey-tile-layer.js +42 -0
  53. package/src/layers/quadkey-tileset-2d.js +36 -0
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.7.8",
5
+ "version": "8.8.0-alpha.3",
6
6
  "publishConfig": {
7
7
  "access": "public"
8
8
  },
@@ -31,12 +31,12 @@
31
31
  "prepublishOnly": "npm run build-bundle && npm run build-bundle -- --env.dev"
32
32
  },
33
33
  "dependencies": {
34
- "@loaders.gl/gis": "^3.1.5",
35
- "@loaders.gl/loader-utils": "^3.1.5",
36
- "@loaders.gl/mvt": "^3.1.5",
37
- "@loaders.gl/tiles": "^3.1.5",
34
+ "@loaders.gl/gis": "^3.2.0-alpha.4",
35
+ "@loaders.gl/loader-utils": "^3.2.0-alpha.4",
36
+ "@loaders.gl/mvt": "^3.2.0-alpha.4",
37
+ "@loaders.gl/tiles": "^3.2.0-alpha.4",
38
38
  "@luma.gl/constants": "^8.5.10",
39
- "@math.gl/web-mercator": "^3.5.7",
39
+ "@math.gl/web-mercator": "3.6.0-alpha.5",
40
40
  "cartocolor": "^4.0.2",
41
41
  "d3-array": "^2.8.0",
42
42
  "d3-color": "^2.0.0",
@@ -53,9 +53,10 @@
53
53
  "peerDependencies": {
54
54
  "@deck.gl/aggregation-layers": "^8.0.0",
55
55
  "@deck.gl/core": "^8.0.0",
56
+ "@deck.gl/extensions": "^8.0.0",
56
57
  "@deck.gl/geo-layers": "^8.0.0",
57
58
  "@deck.gl/layers": "^8.0.0",
58
- "@loaders.gl/core": "^3.1.5"
59
+ "@loaders.gl/core": "^3.0.0"
59
60
  },
60
- "gitHead": "2172dfe62ab2963f755601c1338e98e72cf032e7"
61
+ "gitHead": "edad7cf75b75a137d63ec89d2d644727d3082e25"
61
62
  }
@@ -7,7 +7,8 @@ import {
7
7
  scalePoint,
8
8
  scaleQuantile,
9
9
  scaleQuantize,
10
- scaleSqrt
10
+ scaleSqrt,
11
+ scaleThreshold
11
12
  } from 'd3-scale';
12
13
  import {format as d3Format} from 'd3-format';
13
14
  import moment from 'moment-timezone';
@@ -27,10 +28,13 @@ const SCALE_FUNCS = {
27
28
  point: scalePoint,
28
29
  quantile: scaleQuantile,
29
30
  quantize: scaleQuantize,
30
- sqrt: scaleSqrt
31
+ sqrt: scaleSqrt,
32
+ custom: scaleThreshold
31
33
  };
32
34
  export type SCALE_TYPE = keyof typeof SCALE_FUNCS;
33
35
 
36
+ const UNKNOWN_COLOR = '#868d91';
37
+
34
38
  export const AGGREGATION = {
35
39
  average: 'MEAN',
36
40
  maximum: 'MAX',
@@ -38,6 +42,12 @@ export const AGGREGATION = {
38
42
  sum: 'SUM'
39
43
  };
40
44
 
45
+ export const OPACITY_MAP = {
46
+ getFillColor: 'opacity',
47
+ getLineColor: 'strokeOpacity',
48
+ getTextColor: 'opacity'
49
+ };
50
+
41
51
  const AGGREGATION_FUNC = {
42
52
  'count unique': (values, accessor) => groupSort(values, v => v.length, accessor).length,
43
53
  median,
@@ -67,7 +77,6 @@ const sharedPropMap = {
67
77
  enable3d: 'extruded',
68
78
  elevationScale: 'elevationScale',
69
79
  filled: 'filled',
70
- opacity: 'opacity',
71
80
  strokeColor: 'getLineColor',
72
81
  stroked: 'stroked',
73
82
  thickness: 'getLineWidth',
@@ -179,7 +188,11 @@ function domainFromAttribute(attribute, scaleType: SCALE_TYPE) {
179
188
 
180
189
  function domainFromValues(values, scaleType: SCALE_TYPE) {
181
190
  if (scaleType === 'ordinal') {
182
- return [...new Set(values)].sort();
191
+ return groupSort(
192
+ values,
193
+ g => -g.length,
194
+ d => d
195
+ );
183
196
  } else if (scaleType === 'quantile') {
184
197
  return values.sort((a, b) => a - b);
185
198
  } else if (scaleType === 'log') {
@@ -217,6 +230,10 @@ function normalizeAccessor(accessor, data) {
217
230
  return accessor;
218
231
  }
219
232
 
233
+ export function opacityToAlpha(opacity) {
234
+ return opacity !== undefined ? Math.round(255 * Math.pow(opacity, 1 / 2.2)) : 255;
235
+ }
236
+
220
237
  export function getColorValueAccessor({name}, colorAggregation, data: any) {
221
238
  const aggregator = AGGREGATION_FUNC[colorAggregation];
222
239
  const accessor = values => aggregator(values, p => p[name]);
@@ -226,18 +243,37 @@ export function getColorValueAccessor({name}, colorAggregation, data: any) {
226
243
  export function getColorAccessor(
227
244
  {name},
228
245
  scaleType: SCALE_TYPE,
229
- {colors},
246
+ {colors, colorMap},
230
247
  opacity: number | undefined,
231
248
  data: any
232
249
  ) {
233
250
  const scale = SCALE_FUNCS[scaleType as any]();
234
- scale.domain(calculateDomain(data, name, scaleType));
235
- scale.range(colors);
236
- const alpha = opacity !== undefined ? Math.round(255 * Math.pow(opacity, 1 / 2.2)) : 255;
251
+ let domain: (string | number)[] = [];
252
+ let scaleColor: string[] = [];
253
+
254
+ if (Array.isArray(colorMap)) {
255
+ colorMap.forEach(([value, color]) => {
256
+ domain.push(value);
257
+ scaleColor.push(color);
258
+ });
259
+ } else {
260
+ domain = calculateDomain(data, name, scaleType);
261
+ scaleColor = colors;
262
+ }
263
+
264
+ if (scaleType === 'ordinal') {
265
+ domain = domain.slice(0, scaleColor.length);
266
+ }
267
+
268
+ scale.domain(domain);
269
+ scale.range(scaleColor);
270
+ scale.unknown(UNKNOWN_COLOR);
271
+ const alpha = opacityToAlpha(opacity);
237
272
 
238
273
  const accessor = properties => {
239
- const {r, g, b} = rgb(scale(properties[name]));
240
- return [r, g, b, alpha];
274
+ const propertyValue = properties[name];
275
+ const {r, g, b} = rgb(scale(propertyValue));
276
+ return [r, g, b, propertyValue === null ? 0 : alpha];
241
277
  };
242
278
  return normalizeAccessor(accessor, data);
243
279
  }
@@ -20,8 +20,8 @@ export const MAP_TYPES = {
20
20
  TILESET: 'tileset'
21
21
  } as const;
22
22
  export type MapType = ValuesOf<typeof MAP_TYPES>;
23
- export const COLUMNS_SUPPORT = [MAP_TYPES.TABLE];
24
- export const GEO_COLUMN_SUPPORT = [MAP_TYPES.QUERY, MAP_TYPES.TABLE];
23
+ export const COLUMNS_SUPPORT: MapType[] = [MAP_TYPES.TABLE];
24
+ export const GEO_COLUMN_SUPPORT: MapType[] = [MAP_TYPES.QUERY, MAP_TYPES.TABLE];
25
25
 
26
26
  // AVAILABLE FORMATS
27
27
  export const FORMATS = {
@@ -35,6 +35,7 @@ export type Format = ValuesOf<typeof FORMATS>;
35
35
  // AVAILABLE FORMATS FOR TILES
36
36
  export const TILE_FORMATS = {
37
37
  MVT: 'mvt',
38
+ JSON: 'json',
38
39
  GEOJSON: 'geojson',
39
40
  BINARY: 'binary'
40
41
  } as const;
@@ -59,7 +60,7 @@ export interface SchemaField {
59
60
  export interface MapInstantiation extends MapInstantiationFormats {
60
61
  nrows: number;
61
62
  size?: number;
62
- schema?: SchemaField[];
63
+ schema: SchemaField[];
63
64
  }
64
65
 
65
66
  type MapInstantiationFormats = Record<
@@ -112,10 +112,11 @@ type FetchLayerDataParams = {
112
112
  credentials: CloudNativeCredentials;
113
113
  geoColumn?: string;
114
114
  columns?: string[];
115
- schema?: boolean;
116
115
  clientId?: string;
117
116
  format?: Format;
118
117
  formatTiles?: TileFormat;
118
+ aggregationExp?: string;
119
+ aggregationResLevel?: number;
119
120
  };
120
121
 
121
122
  /**
@@ -126,23 +127,27 @@ function getParameters({
126
127
  source,
127
128
  geoColumn,
128
129
  columns,
129
- schema,
130
- clientId
130
+ clientId,
131
+ aggregationExp,
132
+ aggregationResLevel
131
133
  }: Omit<FetchLayerDataParams, 'connection' | 'credentials'>) {
132
134
  const parameters = [encodeParameter('client', clientId || DEFAULT_CLIENT)];
133
- if (schema) {
134
- parameters.push(encodeParameter('schema', true));
135
- }
136
135
 
137
136
  const sourceName = type === MAP_TYPES.QUERY ? 'q' : 'name';
138
137
  parameters.push(encodeParameter(sourceName, source));
139
138
 
140
- if (GEO_COLUMN_SUPPORT.includes(type) && geoColumn) {
139
+ if (geoColumn) {
141
140
  parameters.push(encodeParameter('geo_column', geoColumn));
142
141
  }
143
- if (COLUMNS_SUPPORT.includes(type) && columns) {
142
+ if (columns) {
144
143
  parameters.push(encodeParameter('columns', columns.join(',')));
145
144
  }
145
+ if (aggregationExp) {
146
+ parameters.push(encodeParameter('aggregationExp', aggregationExp));
147
+ }
148
+ if (aggregationResLevel) {
149
+ parameters.push(encodeParameter('aggregationResLevel', aggregationResLevel));
150
+ }
146
151
 
147
152
  return parameters.join('&');
148
153
  }
@@ -154,11 +159,20 @@ export async function mapInstantiation({
154
159
  credentials,
155
160
  geoColumn,
156
161
  columns,
157
- schema,
158
- clientId
162
+ clientId,
163
+ aggregationExp,
164
+ aggregationResLevel
159
165
  }: FetchLayerDataParams): Promise<MapInstantiation> {
160
166
  const baseUrl = `${credentials.mapsUrl}/${connection}/${type}`;
161
- const url = `${baseUrl}?${getParameters({type, source, geoColumn, columns, schema, clientId})}`;
167
+ const url = `${baseUrl}?${getParameters({
168
+ type,
169
+ source,
170
+ geoColumn,
171
+ columns,
172
+ clientId,
173
+ aggregationExp,
174
+ aggregationResLevel
175
+ })}`;
162
176
  const {accessToken} = credentials;
163
177
 
164
178
  if (url.length > MAX_GET_LENGTH && type === MAP_TYPES.QUERY) {
@@ -187,7 +201,11 @@ function checkFetchLayerDataParameters({
187
201
  type,
188
202
  source,
189
203
  connection,
190
- credentials
204
+ credentials,
205
+ geoColumn,
206
+ columns,
207
+ aggregationExp,
208
+ aggregationResLevel
191
209
  }: FetchLayerDataParams) {
192
210
  assert(connection, 'Must define connection');
193
211
  assert(type, 'Must define a type');
@@ -196,12 +214,35 @@ function checkFetchLayerDataParameters({
196
214
  assert(credentials.apiVersion === API_VERSIONS.V3, 'Method only available for v3');
197
215
  assert(credentials.apiBaseUrl, 'Must define apiBaseUrl');
198
216
  assert(credentials.accessToken, 'Must define an accessToken');
217
+
218
+ if (columns) {
219
+ assert(
220
+ COLUMNS_SUPPORT.includes(type),
221
+ `The columns parameter is not supported by type ${type}`
222
+ );
223
+ }
224
+ if (geoColumn) {
225
+ assert(
226
+ GEO_COLUMN_SUPPORT.includes(type),
227
+ `The geoColumn parameter is not supported by type ${type}`
228
+ );
229
+ } else {
230
+ assert(!aggregationExp, 'Have aggregationExp, but geoColumn parameter is missing');
231
+ assert(!aggregationResLevel, 'Have aggregationResLevel, but geoColumn parameter is missing');
232
+ }
233
+
234
+ if (!aggregationExp) {
235
+ assert(
236
+ !aggregationResLevel,
237
+ 'Have aggregationResLevel, but aggregationExp parameter is missing'
238
+ );
239
+ }
199
240
  }
200
241
 
201
242
  export interface FetchLayerDataResult {
202
243
  data: any;
203
- format: Format;
204
- schema?: SchemaField[];
244
+ format?: Format;
245
+ schema: SchemaField[];
205
246
  }
206
247
  export async function fetchLayerData({
207
248
  type,
@@ -212,8 +253,9 @@ export async function fetchLayerData({
212
253
  columns,
213
254
  format,
214
255
  formatTiles,
215
- schema,
216
- clientId
256
+ clientId,
257
+ aggregationExp,
258
+ aggregationResLevel
217
259
  }: FetchLayerDataParams): Promise<FetchLayerDataResult> {
218
260
  // Internally we split data fetching into two parts to allow us to
219
261
  // conditionally fetch the actual data, depending on the metadata state
@@ -226,16 +268,13 @@ export async function fetchLayerData({
226
268
  columns,
227
269
  format,
228
270
  formatTiles,
229
- schema,
230
- clientId
271
+ clientId,
272
+ aggregationExp,
273
+ aggregationResLevel
231
274
  });
232
275
 
233
276
  const data = await requestData({url, format: mapFormat, accessToken});
234
- const result: FetchLayerDataResult = {data, format: mapFormat};
235
- if (schema) {
236
- result.schema = metadata.schema;
237
- }
238
-
277
+ const result: FetchLayerDataResult = {data, format: mapFormat, schema: metadata.schema};
239
278
  return result;
240
279
  }
241
280
 
@@ -248,8 +287,9 @@ async function _fetchDataUrl({
248
287
  columns,
249
288
  format,
250
289
  formatTiles,
251
- schema,
252
- clientId
290
+ clientId,
291
+ aggregationExp,
292
+ aggregationResLevel
253
293
  }: FetchLayerDataParams) {
254
294
  const defaultCredentials = getDefaultCredentials();
255
295
  // Only pick up default credentials if they have been defined for
@@ -258,7 +298,16 @@ async function _fetchDataUrl({
258
298
  ...(defaultCredentials.apiVersion === API_VERSIONS.V3 && defaultCredentials),
259
299
  ...credentials
260
300
  };
261
- checkFetchLayerDataParameters({type, source, connection, credentials: localCreds});
301
+ checkFetchLayerDataParameters({
302
+ type,
303
+ source,
304
+ connection,
305
+ credentials: localCreds,
306
+ geoColumn,
307
+ columns,
308
+ aggregationExp,
309
+ aggregationResLevel
310
+ });
262
311
 
263
312
  if (!localCreds.mapsUrl) {
264
313
  localCreds.mapsUrl = buildMapsUrlFromBase(localCreds.apiBaseUrl);
@@ -271,8 +320,9 @@ async function _fetchDataUrl({
271
320
  credentials: localCreds,
272
321
  geoColumn,
273
322
  columns,
274
- schema,
275
- clientId
323
+ clientId,
324
+ aggregationExp,
325
+ aggregationResLevel
276
326
  });
277
327
  let url: string | null = null;
278
328
  let mapFormat: Format | undefined;
@@ -325,7 +375,6 @@ export async function getData({
325
375
  geoColumn,
326
376
  columns,
327
377
  format,
328
- schema: false,
329
378
  clientId
330
379
  });
331
380
  return layerData.data;
@@ -6,7 +6,9 @@ import {
6
6
  getColorValueAccessor,
7
7
  getSizeAccessor,
8
8
  getTextAccessor,
9
- getTextPixelOffsetAccessor
9
+ getTextPixelOffsetAccessor,
10
+ OPACITY_MAP,
11
+ opacityToAlpha
10
12
  } from './layer-map';
11
13
  import {_flatten as flatten, log} from '@deck.gl/core';
12
14
  import {assert} from '../utils';
@@ -131,10 +133,21 @@ function createStyleProps(config, mapping) {
131
133
  mapProps(config, result, mapping);
132
134
 
133
135
  // Kepler format sometimes omits strokeColor. TODO: remove once we can rely on
134
- // `strokeColor` always being sert when `stroke: true`.
136
+ // `strokeColor` always being set when `stroke: true`.
135
137
  if (result.stroked && !result.getLineColor) {
136
138
  result.getLineColor = result.getFillColor;
137
139
  }
140
+
141
+ for (const colorAccessor in OPACITY_MAP) {
142
+ if (Array.isArray(result[colorAccessor])) {
143
+ const color = [...result[colorAccessor]];
144
+ const opacityKey = OPACITY_MAP[colorAccessor];
145
+ const opacity = config.visConfig[opacityKey];
146
+ color[3] = opacityToAlpha(opacity);
147
+ result[colorAccessor] = color;
148
+ }
149
+ }
150
+
138
151
  result.highlightColor = config.visConfig.enable3d ? [255, 255, 255, 60] : [252, 242, 26, 255];
139
152
  return result;
140
153
  }
@@ -159,7 +172,7 @@ function createChannelProps(visualChannels, type, config, data) {
159
172
  if (!AGGREGATION[colorAggregation]) {
160
173
  result.getColorValue = getColorValueAccessor(colorField, colorAggregation, data);
161
174
  } else {
162
- result.getColorWeight = d => [colorField.name];
175
+ result.getColorWeight = d => d[colorField.name];
163
176
  }
164
177
  }
165
178
  } else if (colorField) {
@@ -167,13 +180,15 @@ function createChannelProps(visualChannels, type, config, data) {
167
180
  colorField,
168
181
  colorScale,
169
182
  visConfig.colorRange,
170
- 1, // Rely on layer opacity
183
+ visConfig.opacity,
171
184
  data
172
185
  );
173
186
  }
174
187
 
175
188
  if (strokeColorField) {
176
- const opacity = visConfig.strokeOpacity !== undefined ? visConfig.strokeOpacity : 1;
189
+ const fallbackOpacity = type === 'point' ? visConfig.opacity : 1;
190
+ const opacity =
191
+ visConfig.strokeOpacity !== undefined ? visConfig.strokeOpacity : fallbackOpacity;
177
192
  result.getLineColor = getColorAccessor(
178
193
  strokeColorField,
179
194
  strokeColorScale,
package/src/index.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  export {getDefaultCredentials, setDefaultCredentials} from './config';
2
2
  export {default as CartoLayer} from './layers/carto-layer';
3
3
  export {default as _CartoTileLayer} from './layers/carto-tile-layer';
4
+ export {default as _H3TileLayer} from './layers/h3-tile-layer';
5
+ export {default as _QuadkeyTileLayer} from './layers/quadkey-tile-layer';
4
6
  export {default as BASEMAP} from './basemap';
5
7
  export {default as colorBins} from './style/color-bins-style';
6
8
  export {default as colorCategories} from './style/color-categories-style';
@@ -16,3 +18,5 @@ export {
16
18
  getData,
17
19
  mapInstantiation as _mapInstantiation
18
20
  } from './api';
21
+
22
+ export type {CartoLayerProps} from './layers/carto-layer';