@carto/api-client 0.5.15 → 0.5.17

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.15",
11
+ "version": "0.5.17",
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": {
@@ -121,7 +122,7 @@
121
122
  "rimraf": "^6.0.1",
122
123
  "semver": "^7.7.1",
123
124
  "thenby": "^1.3.4",
124
- "tinybench": "^4.0.1",
125
+ "tinybench": "^5.0.1",
125
126
  "tsup": "^8.3.6",
126
127
  "typescript": "~5.9.2",
127
128
  "typescript-eslint": "^8.26.1",
@@ -92,7 +92,7 @@ export const STYLE_LAYER_GROUPS: StyleLayerGroup[] = [
92
92
  ];
93
93
 
94
94
  export function applyLayerGroupFilters(
95
- style: any,
95
+ style: any, // this Maplibre/Mapbox style, we don't want to add a dependency on Maplibre
96
96
  visibleLayerGroups: Record<StyleLayerGroupSlug, boolean>
97
97
  ) {
98
98
  if (!Array.isArray(style?.layers)) {
@@ -1,4 +1,8 @@
1
- export {default as BASEMAP} from './basemap-styles.js';
1
+ export {
2
+ default as BASEMAP,
3
+ applyLayerGroupFilters as _applyLayerGroupFilters,
4
+ } from './basemap-styles.js';
5
+ export {getRasterTileLayerStyleProps as _getRasterTileLayerStyleProps} from './raster-layer.js';
2
6
  export {fetchMap} from './fetch-map.js';
3
7
  export type {FetchMapOptions, FetchMapResult} from './fetch-map.js';
4
8
  export type {
@@ -11,3 +15,4 @@ export type {
11
15
  export * from './basemap.js';
12
16
  export * from './layer-map.js';
13
17
  export * from './parse-map.js';
18
+ export {getLog10ScaleSteps as _getLog10ScaleSteps} from './utils.js';
@@ -25,9 +25,11 @@ import {
25
25
  createBinaryProxy,
26
26
  formatDate,
27
27
  formatTimestamp,
28
+ getLog10ScaleSteps,
28
29
  scaleIdentity,
29
30
  } from './utils.js';
30
31
  import type {
32
+ ColorRange,
31
33
  CustomMarkersRange,
32
34
  Dataset,
33
35
  MapLayerConfig,
@@ -38,6 +40,7 @@ import type {
38
40
  import type {ProviderType, SchemaField} from '../types.js';
39
41
  import {DEFAULT_AGGREGATION_EXP_ALIAS} from '../constants-internal.js';
40
42
  import {AggregationTypes} from '../constants.js';
43
+ import type {Attribute, TilejsonResult} from '../sources/types.js';
41
44
 
42
45
  export type D3Scale = {
43
46
  domain: (d?: any) => any[];
@@ -72,7 +75,21 @@ function identity<T>(v: T): T {
72
75
  return v;
73
76
  }
74
77
 
78
+ const hexToRGB = (c: any) => {
79
+ const {r, g, b} = rgb(c);
80
+ return [r, g, b];
81
+ };
82
+
83
+ const rgbToHex = (c: number[]) => {
84
+ const [r, g, b] = c;
85
+ const rStr = r.toString(16).padStart(2, '0');
86
+ const gStr = g.toString(16).padStart(2, '0');
87
+ const bStr = b.toString(16).padStart(2, '0');
88
+ return `#${rStr}${gStr}${bStr}`.toUpperCase();
89
+ };
90
+
75
91
  const UNKNOWN_COLOR = '#868d91';
92
+ const UNKNOWN_COLOR_RGB = hexToRGB(UNKNOWN_COLOR);
76
93
 
77
94
  export const OPACITY_MAP: Record<string, string> = {
78
95
  getFillColor: 'opacity',
@@ -113,6 +130,13 @@ const sharedPropMap = {
113
130
  },
114
131
  };
115
132
 
133
+ const rasterPropsMap = {
134
+ isVisible: 'visible',
135
+ visConfig: {
136
+ opacity: 'opacity',
137
+ },
138
+ };
139
+
116
140
  const customMarkersPropsMap = {
117
141
  color: 'getIconColor',
118
142
  visConfig: {
@@ -174,6 +198,13 @@ export function getLayerProps(
174
198
  );
175
199
  }
176
200
 
201
+ if (type === 'raster') {
202
+ return {
203
+ propMap: rasterPropsMap,
204
+ defaultProps: {},
205
+ };
206
+ }
207
+
177
208
  let basePropMap: any = sharedPropMap;
178
209
  if (config.visConfig?.customMarkers) {
179
210
  basePropMap = mergePropMaps(basePropMap, customMarkersPropsMap);
@@ -195,18 +226,21 @@ export function getLayerProps(
195
226
  }
196
227
 
197
228
  function domainFromAttribute(
198
- attribute: any,
229
+ attribute: Attribute,
199
230
  scaleType: ScaleType,
200
231
  scaleLength: number
201
- ) {
232
+ ): number[] | string[] {
202
233
  if (scaleType === 'ordinal' || scaleType === 'point') {
234
+ if (!attribute.categories) {
235
+ return [0, 1];
236
+ }
203
237
  return attribute.categories
204
238
  .map((c: any) => c.category)
205
239
  .filter((c: any) => c !== undefined && c !== null);
206
240
  }
207
241
 
208
242
  if (scaleType === 'quantile' && attribute.quantiles) {
209
- return attribute.quantiles.global
243
+ return 'global' in attribute.quantiles
210
244
  ? attribute.quantiles.global[scaleLength]
211
245
  : attribute.quantiles[scaleLength];
212
246
  }
@@ -215,7 +249,7 @@ function domainFromAttribute(
215
249
  if (scaleType === 'log' && min === 0) {
216
250
  min = 1e-5;
217
251
  }
218
- return [min, attribute.max];
252
+ return [min ?? 0, attribute.max ?? 1];
219
253
  }
220
254
 
221
255
  function domainFromValues(values: any, scaleType: ScaleType) {
@@ -235,8 +269,8 @@ function domainFromValues(values: any, scaleType: ScaleType) {
235
269
  }
236
270
 
237
271
  function calculateDomain(
238
- data: any,
239
- name: any,
272
+ data: TilejsonResult,
273
+ name: string,
240
274
  scaleType: ScaleType,
241
275
  scaleLength?: number
242
276
  ) {
@@ -244,14 +278,16 @@ function calculateDomain(
244
278
  // Tileset data type
245
279
  const {attributes} = data.tilestats.layers[0];
246
280
  const attribute = attributes.find((a: any) => a.attribute === name);
247
- return domainFromAttribute(attribute, scaleType, scaleLength as number);
281
+ if (attribute) {
282
+ return domainFromAttribute(attribute, scaleType, scaleLength as number);
283
+ }
248
284
  }
249
285
 
250
286
  return [0, 1];
251
287
  }
252
288
 
253
289
  function normalizeAccessor(accessor: any, data: any) {
254
- if (data.features || data.tilestats) {
290
+ if (data.features || data.tilestats || data.raster_metadata) {
255
291
  return (object: any, info: any) => {
256
292
  if (object) {
257
293
  return accessor(object.properties || object.__source.object.properties);
@@ -297,61 +333,101 @@ function findAccessorKey(keys: string[], properties: any): string[] {
297
333
  export function getColorAccessor(
298
334
  {name, colorColumn}: VisualChannelField,
299
335
  scaleType: ScaleType,
300
- {aggregation, range}: {aggregation: string; range: any},
336
+ {aggregation, range}: {aggregation?: string; range: ColorRange},
301
337
  opacity: number | undefined,
302
- data: any
303
- ): {accessor: any; scale: any} {
304
- const scale = calculateLayerScale(
338
+ data: TilejsonResult
339
+ ): {
340
+ accessor: any;
341
+ domain: number[] | string[];
342
+ scaleDomain: number[] | string[];
343
+ range: string[];
344
+ } {
345
+ const {scale, domain} = calculateLayerScale(
305
346
  colorColumn || name,
306
- scaleType,
347
+ colorColumn ? 'identity' : scaleType,
307
348
  range,
308
349
  data
309
350
  );
310
351
  const alpha = opacityToAlpha(opacity);
311
352
 
312
- let accessorKeys = getAccessorKeys(name, aggregation);
353
+ let accessorKeys = getAccessorKeys(colorColumn || name, aggregation);
313
354
  const accessor = (properties: any) => {
314
355
  if (!(accessorKeys[0] in properties)) {
315
356
  accessorKeys = findAccessorKey(accessorKeys, properties);
316
357
  }
317
358
  const propertyValue = properties[accessorKeys[0]];
318
- const {r, g, b} = rgb(scale(propertyValue));
319
- return [r, g, b, propertyValue === null ? 0 : alpha];
359
+ const scaled = scale(propertyValue);
360
+ const rgb = typeof scaled === 'string' ? hexToRGB(scaled) : scaled;
361
+ return [...rgb, propertyValue === null ? 0 : alpha];
362
+ };
363
+ return {
364
+ accessor: normalizeAccessor(accessor, data),
365
+ scaleDomain: scale.domain(),
366
+ domain,
367
+ range: (scale.range() || []).map(rgbToHex),
320
368
  };
321
- return {accessor: normalizeAccessor(accessor, data), scale};
322
369
  }
323
370
 
324
- function calculateLayerScale(
325
- name: any,
371
+ export function calculateLayerScale(
372
+ name: string,
326
373
  scaleType: ScaleType,
327
- range: any,
328
- data: any
329
- ) {
330
- const scale = SCALE_FUNCS[scaleType]();
331
- let domain: (string | number)[] = [];
374
+ range: ColorRange,
375
+ data: TilejsonResult
376
+ ): {scale: D3Scale; domain: string[] | number[]} {
377
+ let domain: string[] | number[] = [];
378
+ let scaleDomain: number[] | undefined;
332
379
  let scaleColor: string[] = [];
380
+ const {colors} = range;
381
+
382
+ if (scaleType === 'custom') {
383
+ domain = calculateDomain(data, name, scaleType, colors.length);
384
+ const [min, max] = domain as number[];
385
+ if (range.uiCustomScaleType === 'logarithmic') {
386
+ scaleDomain = getLog10ScaleSteps({
387
+ min,
388
+ max,
389
+ steps: colors.length,
390
+ });
333
391
 
334
- if (scaleType !== 'identity') {
335
- const {colorMap, colors} = range;
336
-
337
- if (Array.isArray(colorMap)) {
392
+ scaleColor = colors;
393
+ } else if (range.colorMap) {
394
+ const {colorMap} = range;
395
+ scaleDomain = [];
338
396
  colorMap.forEach(([value, color]) => {
339
- domain.push(value);
397
+ (scaleDomain as number[]).push(Number(value));
340
398
  scaleColor.push(color);
341
399
  });
342
- } else {
343
- domain = calculateDomain(data, name, scaleType, colors.length);
344
- scaleColor = colors;
345
400
  }
401
+ } else if (scaleType !== 'identity') {
402
+ domain = calculateDomain(data, name, scaleType, colors.length);
403
+ scaleColor = colors;
346
404
 
347
405
  if (scaleType === 'ordinal') {
348
406
  domain = domain.slice(0, scaleColor.length);
349
407
  }
350
408
  }
351
409
 
410
+ return {
411
+ scale: createColorScale(
412
+ scaleType,
413
+ scaleDomain || domain,
414
+ scaleColor.map(hexToRGB),
415
+ UNKNOWN_COLOR_RGB
416
+ ),
417
+ domain,
418
+ };
419
+ }
420
+
421
+ export function createColorScale<T>(
422
+ scaleType: ScaleType,
423
+ domain: string[] | number[],
424
+ range: T[],
425
+ unknown: T
426
+ ) {
427
+ const scale = SCALE_FUNCS[scaleType]();
352
428
  scale.domain(domain);
353
- scale.range(scaleColor);
354
- scale.unknown!(UNKNOWN_COLOR);
429
+ scale.range(range);
430
+ scale.unknown!(unknown as any);
355
431
 
356
432
  return scale;
357
433
  }
@@ -427,13 +503,22 @@ export function getSizeAccessor(
427
503
  {name}: VisualChannelField,
428
504
  scaleType: ScaleType | undefined,
429
505
  aggregation: string | null | undefined,
430
- range: Iterable<Range> | null | undefined,
431
- data: any
432
- ): {accessor: any; scale: any} {
506
+ range: number[] | undefined,
507
+ data: TilejsonResult
508
+ ): {
509
+ accessor: any;
510
+ domain: number[];
511
+ scaleDomain: number[];
512
+ range: number[] | undefined;
513
+ } {
433
514
  const scale = scaleType ? SCALE_FUNCS[scaleType]() : identity;
434
- if (scaleType) {
515
+ let domain: number[] = [];
516
+ if (scaleType && range) {
435
517
  if (aggregation !== AggregationTypes.Count) {
436
- (scale as D3Scale).domain(calculateDomain(data, name, scaleType));
518
+ domain = calculateDomain(data, name, scaleType) as number[];
519
+ (scale as D3Scale).domain(domain);
520
+ } else {
521
+ domain = (scale as D3Scale).domain();
437
522
  }
438
523
  (scale as D3Scale).range(range);
439
524
  }
@@ -446,7 +531,12 @@ export function getSizeAccessor(
446
531
  const propertyValue = properties[accessorKeys[0]];
447
532
  return scale(propertyValue);
448
533
  };
449
- return {accessor: normalizeAccessor(accessor, data), scale};
534
+ return {
535
+ accessor: normalizeAccessor(accessor, data),
536
+ domain,
537
+ scaleDomain: domain,
538
+ range,
539
+ };
450
540
  }
451
541
 
452
542
  const FORMATS: Record<string, (value: any) => string> = {