@carto/api-client 0.5.15-alpha.raster-2 → 0.5.15-alpha.raster-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.
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-alpha.raster-2",
11
+ "version": "0.5.15-alpha.raster-3",
12
12
  "license": "MIT",
13
13
  "publishConfig": {
14
14
  "access": "public"
@@ -75,7 +75,21 @@ function identity<T>(v: T): T {
75
75
  return v;
76
76
  }
77
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
+
78
91
  const UNKNOWN_COLOR = '#868d91';
92
+ const UNKNOWN_COLOR_RGB = hexToRGB(UNKNOWN_COLOR);
79
93
 
80
94
  export const OPACITY_MAP: Record<string, string> = {
81
95
  getFillColor: 'opacity',
@@ -213,20 +227,9 @@ export function getLayerProps(
213
227
 
214
228
  function domainFromAttribute(
215
229
  attribute: Attribute,
216
- scaleType: ScaleType | 'log10steps',
230
+ scaleType: ScaleType,
217
231
  scaleLength: number
218
232
  ): number[] | string[] {
219
- if (
220
- scaleType === 'log10steps' &&
221
- attribute.min !== undefined &&
222
- attribute.max !== undefined
223
- ) {
224
- return getLog10ScaleSteps({
225
- min: attribute.min,
226
- max: attribute.max,
227
- steps: scaleLength,
228
- });
229
- }
230
233
  if (scaleType === 'ordinal' || scaleType === 'point') {
231
234
  if (!attribute.categories) {
232
235
  return [0, 1];
@@ -268,7 +271,7 @@ function domainFromValues(values: any, scaleType: ScaleType) {
268
271
  function calculateDomain(
269
272
  data: TilejsonResult,
270
273
  name: string,
271
- scaleType: ScaleType | 'log10steps',
274
+ scaleType: ScaleType,
272
275
  scaleLength?: number
273
276
  ) {
274
277
  if (data.tilestats) {
@@ -330,11 +333,16 @@ function findAccessorKey(keys: string[], properties: any): string[] {
330
333
  export function getColorAccessor(
331
334
  {name, colorColumn}: VisualChannelField,
332
335
  scaleType: ScaleType,
333
- {aggregation, range}: {aggregation: string; range: any},
336
+ {aggregation, range}: {aggregation?: string; range: ColorRange},
334
337
  opacity: number | undefined,
335
338
  data: TilejsonResult
336
- ): {accessor: any; scale: any} {
337
- const scale = calculateLayerScale(
339
+ ): {
340
+ accessor: any;
341
+ domain: number[] | string[];
342
+ scaleDomain: number[] | string[];
343
+ range: string[];
344
+ } {
345
+ const {scale, domain} = calculateLayerScale(
338
346
  colorColumn || name,
339
347
  scaleType,
340
348
  range,
@@ -348,10 +356,15 @@ export function getColorAccessor(
348
356
  accessorKeys = findAccessorKey(accessorKeys, properties);
349
357
  }
350
358
  const propertyValue = properties[accessorKeys[0]];
351
- const {r, g, b} = rgb(scale(propertyValue));
359
+ const [r, g, b] = scale(propertyValue);
352
360
  return [r, g, b, propertyValue === null ? 0 : alpha];
353
361
  };
354
- return {accessor: normalizeAccessor(accessor, data), scale};
362
+ return {
363
+ accessor: normalizeAccessor(accessor, data),
364
+ scaleDomain: scale.domain(),
365
+ domain,
366
+ range: scale.range().map(rgbToHex),
367
+ };
355
368
  }
356
369
 
357
370
  export function calculateLayerScale(
@@ -359,14 +372,22 @@ export function calculateLayerScale(
359
372
  scaleType: ScaleType,
360
373
  range: ColorRange,
361
374
  data: TilejsonResult
362
- ) {
375
+ ): {scale: D3Scale; domain: string[] | number[]} {
363
376
  let domain: string[] | number[] = [];
377
+ let scaleDomain: number[] | undefined;
364
378
  let scaleColor: string[] = [];
365
379
  const {colors} = range;
366
380
 
367
381
  if (scaleType === 'custom') {
368
382
  if (range.uiCustomScaleType === 'logarithmic') {
369
- domain = calculateDomain(data, name, 'log10steps', colors.length);
383
+ domain = calculateDomain(data, name, scaleType, colors.length);
384
+ const [min, max] = domain as number[];
385
+ scaleDomain = getLog10ScaleSteps({
386
+ min,
387
+ max,
388
+ steps: colors.length,
389
+ });
390
+
370
391
  scaleColor = colors;
371
392
  } else if (range.colorMap) {
372
393
  const {colorMap} = range;
@@ -384,7 +405,15 @@ export function calculateLayerScale(
384
405
  }
385
406
  }
386
407
 
387
- return createColorScale(scaleType, domain, scaleColor, UNKNOWN_COLOR);
408
+ return {
409
+ scale: createColorScale(
410
+ scaleType,
411
+ scaleDomain || domain,
412
+ scaleColor.map(hexToRGB),
413
+ UNKNOWN_COLOR_RGB
414
+ ),
415
+ domain,
416
+ };
388
417
  }
389
418
 
390
419
  export function createColorScale<T>(
@@ -472,13 +501,22 @@ export function getSizeAccessor(
472
501
  {name}: VisualChannelField,
473
502
  scaleType: ScaleType | undefined,
474
503
  aggregation: string | null | undefined,
475
- range: Iterable<Range> | null | undefined,
504
+ range: number[] | undefined,
476
505
  data: TilejsonResult
477
- ): {accessor: any; scale: any} {
506
+ ): {
507
+ accessor: any;
508
+ domain: number[];
509
+ scaleDomain: number[];
510
+ range: number[] | undefined;
511
+ } {
478
512
  const scale = scaleType ? SCALE_FUNCS[scaleType]() : identity;
479
- if (scaleType) {
513
+ let domain: number[] = [];
514
+ if (scaleType && range) {
480
515
  if (aggregation !== AggregationTypes.Count) {
481
- (scale as D3Scale).domain(calculateDomain(data, name, scaleType));
516
+ domain = calculateDomain(data, name, scaleType) as number[];
517
+ (scale as D3Scale).domain(domain);
518
+ } else {
519
+ domain = (scale as D3Scale).domain();
482
520
  }
483
521
  (scale as D3Scale).range(range);
484
522
  }
@@ -491,7 +529,12 @@ export function getSizeAccessor(
491
529
  const propertyValue = properties[accessorKeys[0]];
492
530
  return scale(propertyValue);
493
531
  };
494
- return {accessor: normalizeAccessor(accessor, data), scale};
532
+ return {
533
+ accessor: normalizeAccessor(accessor, data),
534
+ domain,
535
+ scaleDomain: domain,
536
+ range,
537
+ };
495
538
  }
496
539
 
497
540
  const FORMATS: Record<string, (value: any) => string> = {
@@ -16,7 +16,6 @@ import {
16
16
  TEXT_NUMBER_FORMATTER,
17
17
  TEXT_LABEL_INDEX,
18
18
  TEXT_OUTLINE_OPACITY,
19
- type D3Scale,
20
19
  type ScaleType,
21
20
  } from './layer-map.js';
22
21
 
@@ -39,10 +38,15 @@ import {
39
38
  import type {TilejsonResult} from '../sources/types.js';
40
39
 
41
40
  export type Scale = {
41
+ type: ScaleType;
42
42
  field: VisualChannelField;
43
+
44
+ /** Natural domain of the scale, as defined by the data */
43
45
  domain: string[] | number[];
44
- range: string[] | number[];
45
- type: ScaleType;
46
+
47
+ /** Domain of the user to construct d3 scale */
48
+ scaleDomain?: string[] | number[];
49
+ range?: string[] | number[];
46
50
  };
47
51
 
48
52
  export type ScaleKey =
@@ -52,11 +56,13 @@ export type ScaleKey =
52
56
  | 'elevation'
53
57
  | 'weight';
54
58
 
59
+ export type Scales = Partial<Record<ScaleKey, Scale>>;
60
+
55
61
  export type LayerDescriptor = {
56
62
  type: LayerType;
57
63
  props: Record<string, any>;
58
64
  filters?: Filters;
59
- scales: Partial<Record<ScaleKey, Scale>>;
65
+ scales: Scales;
60
66
  };
61
67
 
62
68
  export type ParseMapResult = {
@@ -232,7 +238,7 @@ function createStyleProps(config: MapLayerConfig, mapping: any) {
232
238
  if (Array.isArray(result[colorAccessor])) {
233
239
  const color = [...result[colorAccessor]];
234
240
  const opacityKey = OPACITY_MAP[colorAccessor];
235
- const opacity = config.visConfig[opacityKey as keyof VisConfig];
241
+ const opacity = config.visConfig[opacityKey as keyof VisConfig] as number;
236
242
  color[3] = opacityToAlpha(opacity);
237
243
  result[colorAccessor] = color;
238
244
  }
@@ -244,15 +250,6 @@ function createStyleProps(config: MapLayerConfig, mapping: any) {
244
250
  return result;
245
251
  }
246
252
 
247
- function domainAndRangeFromScale(
248
- scale: D3Scale
249
- ): Pick<Scale, 'domain' | 'range'> {
250
- return {
251
- domain: scale.domain(),
252
- range: scale.range(),
253
- };
254
- }
255
-
256
253
  function createChannelProps(
257
254
  id: string,
258
255
  layerType: LayerType,
@@ -264,17 +261,6 @@ function createChannelProps(
264
261
  channelProps: Record<string, any>;
265
262
  scales: Partial<Record<ScaleKey, Scale>>;
266
263
  } {
267
- const {
268
- colorField,
269
- colorScale,
270
- radiusField,
271
- radiusScale,
272
- strokeColorField,
273
- strokeColorScale,
274
- sizeField: strokeWidthField,
275
- sizeScale: strokeWidthScale,
276
- weightField,
277
- } = visualChannels;
278
264
  if (layerType === 'raster') {
279
265
  const rasterMetadata = data.raster_metadata;
280
266
  if (!rasterMetadata) {
@@ -291,7 +277,7 @@ function createChannelProps(
291
277
  rasterMetadata,
292
278
  visualChannels,
293
279
  }),
294
- scales: {},
280
+ scales: {}, // TODO
295
281
  };
296
282
  } else {
297
283
  return {
@@ -301,42 +287,38 @@ function createChannelProps(
301
287
  rasterMetadata,
302
288
  }),
303
289
  scales: {
304
- ...(colorField && {
305
- fillColor: {
306
- field: colorField,
307
- type: 'ordinal',
308
- domain: [],
309
- range: [],
310
- },
311
- }),
290
+ // TODO
312
291
  },
313
292
  };
314
293
  }
315
294
  }
316
- const {heightField, heightScale} = visualChannels;
317
295
  const {textLabel, visConfig} = config;
318
296
  const result: Record<string, any> = {};
319
297
  const updateTriggers: Record<string, any> = {};
320
298
 
321
299
  const scales: Record<string, Scale> = {};
322
300
 
323
- if (colorField) {
324
- const {colorAggregation: aggregation, colorRange: range} = visConfig;
325
- const {accessor, scale} = getColorAccessor(
326
- colorField,
327
- colorScale!,
328
- {aggregation, range},
329
- visConfig.opacity,
330
- data
331
- );
332
- result.getFillColor = accessor;
333
- scales.fillColor = updateTriggers.getFillColor = {
334
- field: colorField,
335
- type: colorScale!,
336
- ...domainAndRangeFromScale(scale),
337
- };
338
- } else if (visConfig.filled) {
339
- scales.fillColor = {} as any;
301
+ // fill color
302
+ {
303
+ const {colorField, colorScale} = visualChannels;
304
+ const {colorRange, colorAggregation} = visConfig;
305
+ if (colorField && colorScale && colorRange) {
306
+ const {accessor, ...scaleProps} = getColorAccessor(
307
+ colorField,
308
+ colorScale,
309
+ {aggregation: colorAggregation, range: colorRange},
310
+ visConfig.opacity,
311
+ data
312
+ );
313
+ result.getFillColor = accessor;
314
+ scales.fillColor = updateTriggers.getFillColor = {
315
+ field: colorField,
316
+ type: colorScale,
317
+ ...scaleProps,
318
+ };
319
+ } else {
320
+ scales.fillColor = {} as any;
321
+ }
340
322
  }
341
323
 
342
324
  if (layerType === 'clusterTile') {
@@ -402,87 +384,115 @@ function createChannelProps(
402
384
  };
403
385
  }
404
386
 
405
- if (radiusField) {
406
- const {accessor, scale} = getSizeAccessor(
407
- radiusField,
408
- radiusScale,
409
- visConfig.sizeAggregation,
410
- visConfig.radiusRange || visConfig.sizeRange,
411
- data
412
- );
413
- result.getPointRadius = accessor;
414
- scales.pointRadius = updateTriggers.getPointRadius = {
415
- field: radiusField,
416
- type: radiusScale || 'identity',
417
- ...domainAndRangeFromScale(scale),
418
- };
387
+ // point radius
388
+ {
389
+ const radiusRange = visConfig.radiusRange;
390
+ const {radiusField, radiusScale} = visualChannels;
391
+ if (radiusField && radiusRange && radiusScale) {
392
+ const {accessor, ...scaleProps} = getSizeAccessor(
393
+ radiusField,
394
+ radiusScale,
395
+ visConfig.sizeAggregation,
396
+ radiusRange,
397
+ data
398
+ );
399
+ result.getPointRadius = accessor;
400
+ scales.pointRadius = updateTriggers.getPointRadius = {
401
+ field: radiusField,
402
+ type: radiusScale,
403
+ ...scaleProps,
404
+ };
405
+ }
419
406
  }
420
407
 
421
- if (strokeColorField) {
422
- const opacity =
423
- visConfig.strokeOpacity !== undefined ? visConfig.strokeOpacity : 1;
424
- const {strokeColorAggregation: aggregation, strokeColorRange: range} =
425
- visConfig;
426
- const {accessor, scale} = getColorAccessor(
427
- strokeColorField,
428
- strokeColorScale!,
429
- {aggregation, range},
430
- opacity,
431
- data
432
- );
433
- result.getLineColor = accessor;
434
- scales.lineColor = updateTriggers.getLineColor = {
435
- field: strokeColorField,
436
- type: strokeColorScale!,
437
- ...domainAndRangeFromScale(scale),
438
- };
408
+ // stroke/ouline color
409
+ {
410
+ const strokeColorRange = visConfig.strokeColorRange;
411
+ const {strokeColorScale, strokeColorField} = visualChannels;
412
+ if (strokeColorField && strokeColorRange && strokeColorScale) {
413
+ const {strokeColorAggregation: aggregation} = visConfig;
414
+ const opacity =
415
+ visConfig.strokeOpacity !== undefined ? visConfig.strokeOpacity : 1;
416
+
417
+ const {accessor, ...scaleProps} = getColorAccessor(
418
+ strokeColorField,
419
+ strokeColorScale,
420
+ {aggregation, range: strokeColorRange},
421
+ opacity,
422
+ data
423
+ );
424
+ result.getLineColor = accessor;
425
+ scales.lineColor = updateTriggers.getLineColor = {
426
+ field: strokeColorField,
427
+ type: strokeColorScale,
428
+ ...scaleProps,
429
+ };
430
+ }
439
431
  }
440
- if (strokeWidthField) {
441
- const {accessor, scale} = getSizeAccessor(
442
- strokeWidthField,
443
- strokeWidthScale,
444
- visConfig.sizeAggregation,
445
- visConfig.sizeRange,
446
- data
447
- );
448
- result.getLineWidth = accessor;
449
- scales.lineWidth = updateTriggers.getLineWidth = {
450
- field: strokeWidthField,
451
- type: strokeWidthScale || 'identity',
452
- ...domainAndRangeFromScale(scale),
453
- };
432
+
433
+ // stroke/line width
434
+ {
435
+ const {sizeField: strokeWidthField, sizeScale: strokeWidthScale} =
436
+ visualChannels;
437
+ const {sizeRange, sizeAggregation} = visConfig;
438
+
439
+ if (strokeWidthField && sizeRange) {
440
+ const {accessor, ...scaleProps} = getSizeAccessor(
441
+ strokeWidthField,
442
+ strokeWidthScale,
443
+ sizeAggregation,
444
+ sizeRange,
445
+ data
446
+ );
447
+ result.getLineWidth = accessor;
448
+ scales.lineWidth = updateTriggers.getLineWidth = {
449
+ field: strokeWidthField,
450
+ type: strokeWidthScale || 'identity',
451
+ ...scaleProps,
452
+ };
453
+ }
454
454
  }
455
455
 
456
- if (heightField && visConfig.enable3d) {
457
- const {accessor, scale} = getSizeAccessor(
458
- heightField,
459
- heightScale,
460
- visConfig.heightAggregation,
461
- visConfig.heightRange || visConfig.sizeRange,
462
- data
463
- );
464
- result.getElevation = accessor;
465
- scales.elevation = updateTriggers.getElevation = {
466
- field: heightField,
467
- type: heightScale || 'identity',
468
- ...domainAndRangeFromScale(scale),
469
- };
456
+ // height / elevation
457
+ {
458
+ const {enable3d, heightRange} = visConfig;
459
+ const {heightField, heightScale} = visualChannels;
460
+ if (heightField && heightRange && enable3d) {
461
+ const {accessor, ...scaleProps} = getSizeAccessor(
462
+ heightField,
463
+ heightScale,
464
+ visConfig.heightAggregation,
465
+ heightRange,
466
+ data
467
+ );
468
+ result.getElevation = accessor;
469
+ scales.elevation = updateTriggers.getElevation = {
470
+ field: heightField,
471
+ type: heightScale || 'identity',
472
+ ...scaleProps,
473
+ };
474
+ }
470
475
  }
471
476
 
472
- if (weightField) {
473
- const {accessor, scale} = getSizeAccessor(
474
- weightField,
475
- undefined,
476
- visConfig.weightAggregation,
477
- undefined,
478
- data
479
- );
480
- result.getWeight = accessor;
481
- scales.weight = updateTriggers.getWeight = {
482
- field: weightField,
483
- type: 'identity' as ScaleType,
484
- ...domainAndRangeFromScale(scale),
485
- };
477
+ // weight
478
+ {
479
+ const {weightField} = visualChannels;
480
+ const {weightAggregation} = visConfig;
481
+ if (weightField && weightAggregation) {
482
+ const {accessor, ...scaleProps} = getSizeAccessor(
483
+ weightField,
484
+ undefined,
485
+ weightAggregation,
486
+ undefined,
487
+ data
488
+ );
489
+ result.getWeight = accessor;
490
+ scales.weight = updateTriggers.getWeight = {
491
+ field: weightField,
492
+ type: 'identity' as ScaleType,
493
+ ...scaleProps,
494
+ };
495
+ }
486
496
  }
487
497
 
488
498
  if (visConfig.customMarkers) {
@@ -63,7 +63,7 @@ export type VisConfig = {
63
63
  opacity?: number;
64
64
  enable3d?: boolean;
65
65
 
66
- colorAggregation?: any;
66
+ colorAggregation?: string;
67
67
  colorRange: ColorRange;
68
68
 
69
69
  customMarkers?: boolean;
@@ -73,17 +73,17 @@ export type VisConfig = {
73
73
  radius: number;
74
74
  radiusRange?: number[];
75
75
 
76
- sizeAggregation?: any;
77
- sizeRange?: any;
76
+ sizeAggregation?: string;
77
+ sizeRange?: number[];
78
78
 
79
- strokeColorAggregation?: any;
79
+ strokeColorAggregation?: string;
80
80
  strokeOpacity?: number;
81
81
  strokeColorRange?: ColorRange;
82
82
 
83
- heightRange?: any;
84
- heightAggregation?: any;
83
+ heightRange?: number[];
84
+ heightAggregation?: string;
85
85
 
86
- weightAggregation?: any;
86
+ weightAggregation?: string;
87
87
 
88
88
  // type = clusterTile
89
89
  clusterLevel?: number;