@carto/api-client 0.5.14 → 0.5.15-alpha.raster-0

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/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "homepage": "https://github.com/CartoDB/carto-api-client#readme",
9
9
  "author": "Don McCurdy <donmccurdy@carto.com>",
10
10
  "packageManager": "yarn@4.3.1",
11
- "version": "0.5.14",
11
+ "version": "0.5.15-alpha.raster-0",
12
12
  "license": "MIT",
13
13
  "publishConfig": {
14
14
  "access": "public"
@@ -71,6 +71,7 @@
71
71
  "d3-format": "^3.1.0",
72
72
  "d3-scale": "^4.0.2",
73
73
  "h3-js": "^4.1.0",
74
+ "jsep": "^1.4.0",
74
75
  "quadbin": "^0.4.1-alpha.0"
75
76
  },
76
77
  "devDependencies": {
@@ -131,5 +132,6 @@
131
132
  "resolutions": {
132
133
  "@carto/api-client": "portal:./",
133
134
  "rollup": "^4.20.0"
134
- }
135
+ },
136
+ "stableVersion": "0.5.14"
135
137
  }
@@ -1,4 +1,5 @@
1
1
  export {default as BASEMAP} from './basemap-styles.js';
2
+ export {getRasterTileLayerStyleProps as _getRasterTileLayerStyleProps} from './raster-layer.js';
2
3
  export {fetchMap} from './fetch-map.js';
3
4
  export type {FetchMapOptions, FetchMapResult} from './fetch-map.js';
4
5
  export type {
@@ -28,6 +28,7 @@ import {
28
28
  scaleIdentity,
29
29
  } from './utils.js';
30
30
  import type {
31
+ ColorRange,
31
32
  CustomMarkersRange,
32
33
  Dataset,
33
34
  MapLayerConfig,
@@ -38,6 +39,7 @@ import type {
38
39
  import type {ProviderType, SchemaField} from '../types.js';
39
40
  import {DEFAULT_AGGREGATION_EXP_ALIAS} from '../constants-internal.js';
40
41
  import {AggregationTypes} from '../constants.js';
42
+ import type {TilejsonResult} from '../sources/types.js';
41
43
 
42
44
  export type D3Scale = {
43
45
  domain: (d?: any) => any[];
@@ -113,6 +115,13 @@ const sharedPropMap = {
113
115
  },
114
116
  };
115
117
 
118
+ const rasterPropsMap = {
119
+ isVisible: 'visible',
120
+ visConfig: {
121
+ opacity: 'opacity',
122
+ },
123
+ };
124
+
116
125
  const customMarkersPropsMap = {
117
126
  color: 'getIconColor',
118
127
  visConfig: {
@@ -174,6 +183,13 @@ export function getLayerProps(
174
183
  );
175
184
  }
176
185
 
186
+ if (type === 'raster') {
187
+ return {
188
+ propMap: rasterPropsMap,
189
+ defaultProps: {},
190
+ };
191
+ }
192
+
177
193
  let basePropMap: any = sharedPropMap;
178
194
  if (config.visConfig?.customMarkers) {
179
195
  basePropMap = mergePropMaps(basePropMap, customMarkersPropsMap);
@@ -200,6 +216,9 @@ function domainFromAttribute(
200
216
  scaleLength: number
201
217
  ) {
202
218
  if (scaleType === 'ordinal' || scaleType === 'point') {
219
+ if (!attribute.categories) {
220
+ return [0, 1];
221
+ }
203
222
  return attribute.categories
204
223
  .map((c: any) => c.category)
205
224
  .filter((c: any) => c !== undefined && c !== null);
@@ -235,8 +254,8 @@ function domainFromValues(values: any, scaleType: ScaleType) {
235
254
  }
236
255
 
237
256
  function calculateDomain(
238
- data: any,
239
- name: any,
257
+ data: TilejsonResult,
258
+ name: string,
240
259
  scaleType: ScaleType,
241
260
  scaleLength?: number
242
261
  ) {
@@ -251,7 +270,7 @@ function calculateDomain(
251
270
  }
252
271
 
253
272
  function normalizeAccessor(accessor: any, data: any) {
254
- if (data.features || data.tilestats) {
273
+ if (data.features || data.tilestats || data.raster_metadata) {
255
274
  return (object: any, info: any) => {
256
275
  if (object) {
257
276
  return accessor(object.properties || object.__source.object.properties);
@@ -321,14 +340,13 @@ export function getColorAccessor(
321
340
  return {accessor: normalizeAccessor(accessor, data), scale};
322
341
  }
323
342
 
324
- function calculateLayerScale(
325
- name: any,
343
+ export function calculateLayerScale(
344
+ name: string,
326
345
  scaleType: ScaleType,
327
- range: any,
328
- data: any
346
+ range: ColorRange,
347
+ data: TilejsonResult
329
348
  ) {
330
- const scale = SCALE_FUNCS[scaleType]();
331
- let domain: (string | number)[] = [];
349
+ let domain: string[] | number[] = [];
332
350
  let scaleColor: string[] = [];
333
351
 
334
352
  if (scaleType !== 'identity') {
@@ -336,7 +354,7 @@ function calculateLayerScale(
336
354
 
337
355
  if (Array.isArray(colorMap)) {
338
356
  colorMap.forEach(([value, color]) => {
339
- domain.push(value);
357
+ (domain as string[]).push(value);
340
358
  scaleColor.push(color);
341
359
  });
342
360
  } else {
@@ -349,9 +367,19 @@ function calculateLayerScale(
349
367
  }
350
368
  }
351
369
 
370
+ return createColorScale(scaleType, domain, scaleColor, UNKNOWN_COLOR);
371
+ }
372
+
373
+ export function createColorScale<T>(
374
+ scaleType: ScaleType,
375
+ domain: string[] | number[],
376
+ range: T[],
377
+ unknown: T
378
+ ) {
379
+ const scale = SCALE_FUNCS[scaleType]();
352
380
  scale.domain(domain);
353
- scale.range(scaleColor);
354
- scale.unknown!(UNKNOWN_COLOR);
381
+ scale.range(range);
382
+ scale.unknown!(unknown as any);
355
383
 
356
384
  return scale;
357
385
  }
@@ -32,6 +32,10 @@ import type {
32
32
  VisualChannelField,
33
33
  } from './types.js';
34
34
  import {isRemoteCalculationSupported} from './utils.js';
35
+ import {
36
+ getRasterTileLayerStylePropsRgb,
37
+ getRasterTileLayerStylePropsScaledBand,
38
+ } from './raster-layer.js';
35
39
 
36
40
  export type Scale = {
37
41
  field: VisualChannelField;
@@ -40,11 +44,18 @@ export type Scale = {
40
44
  type: ScaleType;
41
45
  };
42
46
 
47
+ export type ScaleKey =
48
+ | 'fillColor'
49
+ | 'pointRadius'
50
+ | 'lineColor'
51
+ | 'elevation'
52
+ | 'weight';
53
+
43
54
  export type LayerDescriptor = {
44
55
  type: LayerType;
45
56
  props: Record<string, any>;
46
57
  filters?: Filters;
47
- scales: Record<ScaleKey, Scale>;
58
+ scales: Partial<Record<ScaleKey, Scale>>;
48
59
  };
49
60
 
50
61
  export type ParseMapResult = {
@@ -68,13 +79,62 @@ export type ParseMapResult = {
68
79
  layers: LayerDescriptor[];
69
80
  };
70
81
 
82
+ export function getLayerDescriptor({
83
+ mapConfig,
84
+ layer,
85
+ dataset,
86
+ }: {
87
+ mapConfig: KeplerMapConfig;
88
+ layer: MapConfigLayer;
89
+ dataset: Dataset;
90
+ }) {
91
+ const {filters, visState} = mapConfig;
92
+ const {layerBlending, interactionConfig} = visState;
93
+ const {id, type, config, visualChannels} = layer;
94
+ const {data, id: datasetId} = dataset;
95
+
96
+ const {propMap, defaultProps} = getLayerProps(type, config, dataset);
97
+
98
+ const styleProps = createStyleProps(config, propMap);
99
+
100
+ const {channelProps, scales} = createChannelProps(
101
+ id,
102
+ type,
103
+ config,
104
+ visualChannels,
105
+ data,
106
+ dataset
107
+ );
108
+ const layerDescriptor: LayerDescriptor = {
109
+ type,
110
+ filters:
111
+ isEmptyObject(filters) || isRemoteCalculationSupported(dataset)
112
+ ? undefined
113
+ : filters[datasetId],
114
+ props: {
115
+ id,
116
+ data,
117
+ ...defaultProps,
118
+ ...createInteractionProps(interactionConfig),
119
+ ...styleProps,
120
+ ...channelProps,
121
+ ...createParametersProp(layerBlending, styleProps.parameters || {}), // Must come after style
122
+ ...createLoadOptions(data.accessToken),
123
+ },
124
+ scales,
125
+ };
126
+ return layerDescriptor;
127
+ }
128
+
71
129
  export function parseMap(json: any) {
72
130
  const {keplerMapConfig, datasets, token} = json;
73
131
  assert(keplerMapConfig.version === 'v1', 'Only support Kepler v1');
74
- const config = keplerMapConfig.config as KeplerMapConfig;
75
- const {filters, mapState, mapStyle, popupSettings, legendSettings} = config;
76
- const {layers, layerBlending, interactionConfig} = config.visState;
132
+ const mapConfig = keplerMapConfig.config as KeplerMapConfig;
133
+ const {mapState, mapStyle, popupSettings, legendSettings, visState} =
134
+ mapConfig;
135
+ const {layers} = visState;
77
136
 
137
+ const layersReverse = [...layers].reverse();
78
138
  return {
79
139
  id: json.id,
80
140
  title: json.title,
@@ -87,57 +147,24 @@ export function parseMap(json: any) {
87
147
  popupSettings,
88
148
  legendSettings,
89
149
  token,
90
- layers: layers
91
- .reverse()
92
- .map(({id, type, config, visualChannels}: MapConfigLayer) => {
93
- try {
94
- const {dataId} = config;
95
- const dataset: Dataset | null = datasets.find(
96
- (d: any) => d.id === dataId
97
- );
98
- assert(dataset, `No dataset matching dataId: ${dataId}`);
99
- const {data} = dataset;
100
- assert(data, `No data loaded for dataId: ${dataId}`);
101
-
102
- const {propMap, defaultProps} = getLayerProps(type, config, dataset);
103
-
104
- const styleProps = createStyleProps(config, propMap);
105
-
106
- const {channelProps, scales} = createChannelProps(
107
- id,
108
- type,
109
- config,
110
- visualChannels,
111
- data,
112
- dataset
113
- );
114
- const layer: LayerDescriptor = {
115
- type,
116
- filters:
117
- isEmptyObject(filters) || isRemoteCalculationSupported(dataset)
118
- ? undefined
119
- : filters[dataId],
120
- props: {
121
- id,
122
- data,
123
- ...defaultProps,
124
- ...createInteractionProps(interactionConfig),
125
- ...styleProps,
126
- ...channelProps,
127
- ...createParametersProp(
128
- layerBlending,
129
- styleProps.parameters || {}
130
- ), // Must come after style
131
- ...createLoadOptions(token),
132
- },
133
- scales,
134
- };
135
- return layer;
136
- } catch (e: any) {
137
- console.error(e.message);
138
- return undefined;
139
- }
140
- }),
150
+ layers: layersReverse.map((layer: MapConfigLayer) => {
151
+ try {
152
+ const {dataId} = layer.config;
153
+ const dataset: Dataset | null = datasets.find(
154
+ (d: any) => d.id === dataId
155
+ );
156
+ assert(dataset, `No dataset matching dataId: ${dataId}`);
157
+ const layerDescriptor = getLayerDescriptor({
158
+ mapConfig,
159
+ layer,
160
+ dataset,
161
+ });
162
+ return layerDescriptor;
163
+ } catch (e: any) {
164
+ console.error(e.message);
165
+ return undefined;
166
+ }
167
+ }),
141
168
  };
142
169
  }
143
170
 
@@ -225,13 +252,6 @@ function domainAndRangeFromScale(
225
252
  };
226
253
  }
227
254
 
228
- export type ScaleKey =
229
- | 'fillColor'
230
- | 'pointRadius'
231
- | 'lineColor'
232
- | 'elevation'
233
- | 'weight';
234
-
235
255
  function createChannelProps(
236
256
  id: string,
237
257
  layerType: LayerType,
@@ -239,7 +259,10 @@ function createChannelProps(
239
259
  visualChannels: VisualChannels,
240
260
  data: any,
241
261
  dataset: Dataset
242
- ): {channelProps: Record<string, any>; scales: Record<ScaleKey, Scale>} {
262
+ ): {
263
+ channelProps: Record<string, any>;
264
+ scales: Partial<Record<ScaleKey, Scale>>;
265
+ } {
243
266
  const {
244
267
  colorField,
245
268
  colorScale,
@@ -249,9 +272,41 @@ function createChannelProps(
249
272
  strokeColorScale,
250
273
  weightField,
251
274
  } = visualChannels;
275
+ if (layerType === 'raster') {
276
+ const rasterStyleType = config.visConfig.rasterStyleType;
277
+ if (rasterStyleType === 'Rgb') {
278
+ return {
279
+ channelProps: getRasterTileLayerStylePropsRgb({
280
+ layerConfig: config,
281
+ rasterMetadata: data.raster_metadata,
282
+ visualChannels,
283
+ }),
284
+ scales: {},
285
+ };
286
+ } else {
287
+ return {
288
+ channelProps: getRasterTileLayerStylePropsScaledBand({
289
+ layerConfig: config,
290
+ visualChannels,
291
+ rasterMetadata: data.raster_metadata,
292
+ }),
293
+ scales: {
294
+ ...(colorField && {
295
+ fillColor: {
296
+ field: colorField,
297
+ type: 'ordinal',
298
+ domain: [],
299
+ range: [],
300
+ },
301
+ }),
302
+ },
303
+ };
304
+ }
305
+ }
252
306
  const {heightField, heightScale} = visualChannels;
253
307
  const {textLabel, visConfig} = config;
254
308
  const result: Record<string, any> = {};
309
+ const updateTriggers: Record<string, any> = {};
255
310
 
256
311
  const scales: Record<string, Scale> = {};
257
312
 
@@ -265,7 +320,7 @@ function createChannelProps(
265
320
  data
266
321
  );
267
322
  result.getFillColor = accessor;
268
- scales.fillColor = {
323
+ scales.fillColor = updateTriggers.getFillColor = {
269
324
  field: colorField,
270
325
  type: colorScale!,
271
326
  ...domainAndRangeFromScale(scale),
@@ -288,6 +343,8 @@ function createChannelProps(
288
343
  return d.properties[aggregationExpAlias];
289
344
  };
290
345
 
346
+ updateTriggers.getWeight = aggregationExpAlias;
347
+
291
348
  result.getPointRadius = (d: any, info: any) => {
292
349
  return calculateClusterRadius(
293
350
  d.properties,
@@ -296,6 +353,10 @@ function createChannelProps(
296
353
  aggregationExpAlias
297
354
  );
298
355
  };
356
+ updateTriggers.getPointRadius = {
357
+ aggregationExpAlias,
358
+ radiusRange: visConfig.radiusRange,
359
+ };
299
360
 
300
361
  result.textCharacterSet = 'auto';
301
362
  result.textFontFamily = 'Inter, sans';
@@ -305,6 +366,8 @@ function createChannelProps(
305
366
  result.getText = (d: any) =>
306
367
  TEXT_NUMBER_FORMATTER.format(d.properties[aggregationExpAlias]);
307
368
 
369
+ updateTriggers.getText = aggregationExpAlias;
370
+
308
371
  result.getTextColor = config.textLabel[TEXT_LABEL_INDEX].color;
309
372
  result.textOutlineColor = [
310
373
  ...(config.textLabel[TEXT_LABEL_INDEX].outlineColor as number[]),
@@ -322,6 +385,11 @@ function createChannelProps(
322
385
  );
323
386
  return calculateClusterTextFontSize(radius);
324
387
  };
388
+
389
+ updateTriggers.getTextSize = {
390
+ aggregationExpAlias,
391
+ radiusRange: visConfig.radiusRange,
392
+ };
325
393
  }
326
394
 
327
395
  if (radiusField) {
@@ -333,7 +401,7 @@ function createChannelProps(
333
401
  data
334
402
  );
335
403
  result.getPointRadius = accessor;
336
- scales.pointRadius = {
404
+ scales.pointRadius = updateTriggers.getPointRadius = {
337
405
  field: radiusField,
338
406
  type: radiusScale || 'identity',
339
407
  ...domainAndRangeFromScale(scale),
@@ -353,7 +421,7 @@ function createChannelProps(
353
421
  data
354
422
  );
355
423
  result.getLineColor = accessor;
356
- scales.lineColor = {
424
+ scales.lineColor = updateTriggers.getLineColor = {
357
425
  field: strokeColorField,
358
426
  type: strokeColorScale!,
359
427
  ...domainAndRangeFromScale(scale),
@@ -368,7 +436,7 @@ function createChannelProps(
368
436
  data
369
437
  );
370
438
  result.getElevation = accessor;
371
- scales.elevation = {
439
+ scales.elevation = updateTriggers.getElevation = {
372
440
  field: heightField,
373
441
  type: heightScale || 'identity',
374
442
  ...domainAndRangeFromScale(scale),
@@ -384,9 +452,9 @@ function createChannelProps(
384
452
  data
385
453
  );
386
454
  result.getWeight = accessor;
387
- scales.weight = {
455
+ scales.weight = updateTriggers.getWeight = {
388
456
  field: weightField,
389
- type: 'identity',
457
+ type: 'identity' as ScaleType,
390
458
  ...domainAndRangeFromScale(scale),
391
459
  };
392
460
  }
@@ -407,6 +475,12 @@ function createChannelProps(
407
475
  {fallbackUrl: customMarkersUrl, maxIconSize, useMaskedIcons},
408
476
  data
409
477
  );
478
+ updateTriggers.getIcon = {
479
+ customMarkersUrl,
480
+ customMarkersRange,
481
+ maxIconSize,
482
+ useMaskedIcons,
483
+ };
410
484
  result._subLayerProps = {
411
485
  'points-icon': {
412
486
  loadOptions: {
@@ -424,10 +498,12 @@ function createChannelProps(
424
498
 
425
499
  if (getFillColor && useMaskedIcons) {
426
500
  result.getIconColor = getFillColor;
501
+ updateTriggers.getIconColor = updateTriggers.getFillColor;
427
502
  }
428
503
 
429
504
  if (getPointRadius) {
430
505
  result.getIconSize = getPointRadius;
506
+ updateTriggers.getIconSize = updateTriggers.getPointRadius;
431
507
  }
432
508
 
433
509
  if (visualChannels.rotationField) {
@@ -439,6 +515,7 @@ function createChannelProps(
439
515
  data
440
516
  );
441
517
  result.getIconAngle = negateAccessor(accessor);
518
+ updateTriggers.getIconAngle = updateTriggers.getRotationField;
442
519
  }
443
520
  } else if (layerType === 'tileset') {
444
521
  result.pointType = 'circle';
@@ -494,7 +571,13 @@ function createChannelProps(
494
571
  };
495
572
  }
496
573
 
497
- return {channelProps: result, scales};
574
+ return {
575
+ channelProps: {
576
+ ...result,
577
+ updateTriggers,
578
+ },
579
+ scales,
580
+ };
498
581
  }
499
582
 
500
583
  function createLoadOptions(accessToken: string) {