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

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-0",
11
+ "version": "0.5.15-alpha.raster-2",
12
12
  "license": "MIT",
13
13
  "publishConfig": {
14
14
  "access": "public"
@@ -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,7 @@
1
- export {default as BASEMAP} from './basemap-styles.js';
1
+ export {
2
+ default as BASEMAP,
3
+ applyLayerGroupFilters as _applyLayerGroupFilters,
4
+ } from './basemap-styles.js';
2
5
  export {getRasterTileLayerStyleProps as _getRasterTileLayerStyleProps} from './raster-layer.js';
3
6
  export {fetchMap} from './fetch-map.js';
4
7
  export type {FetchMapOptions, FetchMapResult} from './fetch-map.js';
@@ -12,3 +15,4 @@ export type {
12
15
  export * from './basemap.js';
13
16
  export * from './layer-map.js';
14
17
  export * from './parse-map.js';
18
+ export {getLog10ScaleSteps as _getLog10ScaleSteps} from './utils.js';
@@ -25,6 +25,7 @@ import {
25
25
  createBinaryProxy,
26
26
  formatDate,
27
27
  formatTimestamp,
28
+ getLog10ScaleSteps,
28
29
  scaleIdentity,
29
30
  } from './utils.js';
30
31
  import type {
@@ -39,7 +40,7 @@ import type {
39
40
  import type {ProviderType, SchemaField} from '../types.js';
40
41
  import {DEFAULT_AGGREGATION_EXP_ALIAS} from '../constants-internal.js';
41
42
  import {AggregationTypes} from '../constants.js';
42
- import type {TilejsonResult} from '../sources/types.js';
43
+ import type {Attribute, TilejsonResult} from '../sources/types.js';
43
44
 
44
45
  export type D3Scale = {
45
46
  domain: (d?: any) => any[];
@@ -211,10 +212,21 @@ export function getLayerProps(
211
212
  }
212
213
 
213
214
  function domainFromAttribute(
214
- attribute: any,
215
- scaleType: ScaleType,
215
+ attribute: Attribute,
216
+ scaleType: ScaleType | 'log10steps',
216
217
  scaleLength: number
217
- ) {
218
+ ): 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
+ }
218
230
  if (scaleType === 'ordinal' || scaleType === 'point') {
219
231
  if (!attribute.categories) {
220
232
  return [0, 1];
@@ -225,7 +237,7 @@ function domainFromAttribute(
225
237
  }
226
238
 
227
239
  if (scaleType === 'quantile' && attribute.quantiles) {
228
- return attribute.quantiles.global
240
+ return 'global' in attribute.quantiles
229
241
  ? attribute.quantiles.global[scaleLength]
230
242
  : attribute.quantiles[scaleLength];
231
243
  }
@@ -234,7 +246,7 @@ function domainFromAttribute(
234
246
  if (scaleType === 'log' && min === 0) {
235
247
  min = 1e-5;
236
248
  }
237
- return [min, attribute.max];
249
+ return [min ?? 0, attribute.max ?? 1];
238
250
  }
239
251
 
240
252
  function domainFromValues(values: any, scaleType: ScaleType) {
@@ -256,14 +268,16 @@ function domainFromValues(values: any, scaleType: ScaleType) {
256
268
  function calculateDomain(
257
269
  data: TilejsonResult,
258
270
  name: string,
259
- scaleType: ScaleType,
271
+ scaleType: ScaleType | 'log10steps',
260
272
  scaleLength?: number
261
273
  ) {
262
274
  if (data.tilestats) {
263
275
  // Tileset data type
264
276
  const {attributes} = data.tilestats.layers[0];
265
277
  const attribute = attributes.find((a: any) => a.attribute === name);
266
- return domainFromAttribute(attribute, scaleType, scaleLength as number);
278
+ if (attribute) {
279
+ return domainFromAttribute(attribute, scaleType, scaleLength as number);
280
+ }
267
281
  }
268
282
 
269
283
  return [0, 1];
@@ -318,7 +332,7 @@ export function getColorAccessor(
318
332
  scaleType: ScaleType,
319
333
  {aggregation, range}: {aggregation: string; range: any},
320
334
  opacity: number | undefined,
321
- data: any
335
+ data: TilejsonResult
322
336
  ): {accessor: any; scale: any} {
323
337
  const scale = calculateLayerScale(
324
338
  colorColumn || name,
@@ -348,19 +362,22 @@ export function calculateLayerScale(
348
362
  ) {
349
363
  let domain: string[] | number[] = [];
350
364
  let scaleColor: string[] = [];
365
+ const {colors} = range;
351
366
 
352
- if (scaleType !== 'identity') {
353
- const {colorMap, colors} = range;
354
-
355
- if (Array.isArray(colorMap)) {
367
+ if (scaleType === 'custom') {
368
+ if (range.uiCustomScaleType === 'logarithmic') {
369
+ domain = calculateDomain(data, name, 'log10steps', colors.length);
370
+ scaleColor = colors;
371
+ } else if (range.colorMap) {
372
+ const {colorMap} = range;
356
373
  colorMap.forEach(([value, color]) => {
357
374
  (domain as string[]).push(value);
358
375
  scaleColor.push(color);
359
376
  });
360
- } else {
361
- domain = calculateDomain(data, name, scaleType, colors.length);
362
- scaleColor = colors;
363
377
  }
378
+ } else if (scaleType !== 'identity') {
379
+ domain = calculateDomain(data, name, scaleType, colors.length);
380
+ scaleColor = colors;
364
381
 
365
382
  if (scaleType === 'ordinal') {
366
383
  domain = domain.slice(0, scaleColor.length);
@@ -456,7 +473,7 @@ export function getSizeAccessor(
456
473
  scaleType: ScaleType | undefined,
457
474
  aggregation: string | null | undefined,
458
475
  range: Iterable<Range> | null | undefined,
459
- data: any
476
+ data: TilejsonResult
460
477
  ): {accessor: any; scale: any} {
461
478
  const scale = scaleType ? SCALE_FUNCS[scaleType]() : identity;
462
479
  if (scaleType) {
@@ -36,6 +36,7 @@ import {
36
36
  getRasterTileLayerStylePropsRgb,
37
37
  getRasterTileLayerStylePropsScaledBand,
38
38
  } from './raster-layer.js';
39
+ import type {TilejsonResult} from '../sources/types.js';
39
40
 
40
41
  export type Scale = {
41
42
  field: VisualChannelField;
@@ -257,7 +258,7 @@ function createChannelProps(
257
258
  layerType: LayerType,
258
259
  config: MapLayerConfig,
259
260
  visualChannels: VisualChannels,
260
- data: any,
261
+ data: TilejsonResult,
261
262
  dataset: Dataset
262
263
  ): {
263
264
  channelProps: Record<string, any>;
@@ -270,15 +271,24 @@ function createChannelProps(
270
271
  radiusScale,
271
272
  strokeColorField,
272
273
  strokeColorScale,
274
+ sizeField: strokeWidthField,
275
+ sizeScale: strokeWidthScale,
273
276
  weightField,
274
277
  } = visualChannels;
275
278
  if (layerType === 'raster') {
279
+ const rasterMetadata = data.raster_metadata;
280
+ if (!rasterMetadata) {
281
+ return {
282
+ channelProps: {},
283
+ scales: {},
284
+ };
285
+ }
276
286
  const rasterStyleType = config.visConfig.rasterStyleType;
277
287
  if (rasterStyleType === 'Rgb') {
278
288
  return {
279
289
  channelProps: getRasterTileLayerStylePropsRgb({
280
290
  layerConfig: config,
281
- rasterMetadata: data.raster_metadata,
291
+ rasterMetadata,
282
292
  visualChannels,
283
293
  }),
284
294
  scales: {},
@@ -288,7 +298,7 @@ function createChannelProps(
288
298
  channelProps: getRasterTileLayerStylePropsScaledBand({
289
299
  layerConfig: config,
290
300
  visualChannels,
291
- rasterMetadata: data.raster_metadata,
301
+ rasterMetadata,
292
302
  }),
293
303
  scales: {
294
304
  ...(colorField && {
@@ -427,6 +437,22 @@ function createChannelProps(
427
437
  ...domainAndRangeFromScale(scale),
428
438
  };
429
439
  }
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
+ };
454
+ }
455
+
430
456
  if (heightField && visConfig.enable3d) {
431
457
  const {accessor, scale} = getSizeAccessor(
432
458
  heightField,
@@ -13,6 +13,7 @@ import type {
13
13
  VisualChannels,
14
14
  } from './types.js';
15
15
  import {createColorScale, type ScaleType} from './layer-map.js';
16
+ import {getLog10ScaleSteps} from './utils.js';
16
17
 
17
18
  const UNKNOWN_COLOR = [134, 141, 145];
18
19
 
@@ -377,10 +378,11 @@ export function domainFromRasterMetadataBand(
377
378
  }
378
379
  if (scaleType === 'custom') {
379
380
  if (colorRange.uiCustomScaleType === 'logarithmic') {
380
- if (colorRange.colorMap) {
381
- return colorRange.colorMap?.map(([value]) => value) || [];
382
- }
383
- return [band.stats.min, band.stats.max];
381
+ return getLog10ScaleSteps({
382
+ min: band.stats.min,
383
+ max: band.stats.max,
384
+ steps: colorRange.colors.length,
385
+ });
384
386
  } else {
385
387
  // actually custom, read colorMap
386
388
  return colorRange.colorMap?.map(([value]) => value) || [];
@@ -85,3 +85,59 @@ export function formatDate(value: string | number | Date): string {
85
85
  export function formatTimestamp(value: string | number | Date): string {
86
86
  return String(Math.floor(new Date(value).getTime() / 1000));
87
87
  }
88
+
89
+ function roundedPow10(exp: number) {
90
+ // Math.pow(10, less than 4) generates "0.0...009999999999999999" instead of "0.0...01"
91
+ // round it ...
92
+ const raw = Math.pow(10, exp);
93
+ if (exp < 0) {
94
+ const shift = Math.pow(10, -exp);
95
+ return Math.round(raw * shift) / shift;
96
+ }
97
+ return raw;
98
+ }
99
+
100
+ /**
101
+ * Create domain for D3 threshold scale with logarithmic steps.
102
+ *
103
+ * If min is 0, it starts with max and goes down to fill color scale.
104
+ * If max is Infinity, it starts with 10 and goes up to fill color scale.
105
+ * Othersise it starts on first power of 10 that is greater than min.
106
+ *
107
+ * Generates `steps-1` entries, as this is what d3 threshold scale expects
108
+ *
109
+ * @see https://d3js.org/d3-scale/threshold
110
+ */
111
+ export function getLog10ScaleSteps({
112
+ min,
113
+ max,
114
+ steps,
115
+ }: {
116
+ min: number;
117
+ max: number;
118
+ steps: number;
119
+ }): number[] {
120
+ if (min === 0) {
121
+ if (max === Infinity) {
122
+ // count aggregations have [0, Infinity]
123
+ // that will yield [10, 100, 1000, ...]
124
+ return [...Array(steps - 1)].map((_v, i) => roundedPow10(i + 1));
125
+ }
126
+ // if stats.min = 0, we only can attempt to start from max and decrease powers until
127
+ // we use all color buckets ...
128
+ const maxLog = Math.log10(max);
129
+ const endExponent = Math.ceil(maxLog);
130
+ const startExponent = endExponent - steps + 1;
131
+ return [...Array(steps - 1)].map((_v, i) =>
132
+ roundedPow10(startExponent + i)
133
+ );
134
+ } else {
135
+ const minLog = Math.log10(min);
136
+ const startExponent =
137
+ Math.ceil(minLog) === minLog ? minLog + 1 : Math.ceil(minLog);
138
+
139
+ return [...Array(steps - 1)].map((_v, i) =>
140
+ roundedPow10(startExponent + i)
141
+ );
142
+ }
143
+ }
@@ -66,18 +66,6 @@ export function validateVecExprSyntax(
66
66
  return validate(parsed, context);
67
67
  }
68
68
 
69
- export function createValidationContext(
70
- validSymbols: string[]
71
- ): Record<string, unknown> {
72
- return validSymbols.reduce(
73
- (acc, symbol) => {
74
- acc[symbol] = 1;
75
- return acc;
76
- },
77
- {} as Record<string, unknown>
78
- );
79
- }
80
-
81
69
  export type VecExprVecLike =
82
70
  | number[]
83
71
  | Float32Array
package/src/index.ts CHANGED
@@ -2,11 +2,6 @@ export * from './client.js';
2
2
  export * from './constants.js';
3
3
  export * from './deck/index.js';
4
4
  export * from './fetch-map/index.js';
5
- export type {
6
- LayerDescriptor,
7
- LayerType,
8
- _getRasterTileLayerStyleProps,
9
- } from './fetch-map/index.js';
10
5
  export {
11
6
  createVecExprEvaluator as _createVecExprEvaluator,
12
7
  evaluateVecExpr as _evaluateVecExpr,
@@ -292,14 +292,64 @@ export interface Tilestats {
292
292
 
293
293
  export interface Layer {
294
294
  layer: string;
295
+ /** Number of features in the layer. */
295
296
  count: number;
297
+
298
+ /** Number of attributes in the layer. */
296
299
  attributeCount: number;
297
300
  attributes: Attribute[];
301
+
302
+ /** Type of geometry as in geojson geometry type (Point, LineString, Polygon, etc.) */
303
+ geometry?: string;
304
+ }
305
+
306
+ export interface AttributeCategoryItem {
307
+ category: string;
308
+ frequency: number;
309
+ }
310
+
311
+ /**
312
+ * Quantiles by number of buckets.
313
+ *
314
+ * Example:
315
+ * ```ts
316
+ * {
317
+ * // for 3 buckets, first 1/3 of items lies in range [min, 20], second 1/3 is in [20, 40], and last 1/3 is in [40, max]
318
+ * 3: [20, 40],
319
+ * 4: [20, 30, 50], for 4 buckets ...
320
+ * }
321
+ * ```
322
+ */
323
+ export interface QuantileStats {
324
+ [bucketCount: number]: number[];
298
325
  }
299
326
 
300
327
  export interface Attribute {
301
- attribute: string;
328
+ /**
329
+ * String, Number, Timestamp, Boolean
330
+ */
302
331
  type: string;
332
+
333
+ /**
334
+ * Attribute name.
335
+ */
336
+ attribute: string;
337
+
338
+ // Stats for numeric attributes
339
+ min?: number;
340
+ max?: number;
341
+ sum?: number;
342
+
343
+ /** Quantiles by number of buckets */
344
+ quantiles?:
345
+ | {
346
+ // Quantile stats for numeric attributes in static spatial index tilesets are enclosed in extra global object
347
+ global: QuantileStats;
348
+ }
349
+ | QuantileStats;
350
+
351
+ // Stats for string/boolean attributes
352
+ categories?: AttributeCategoryItem[];
303
353
  }
304
354
 
305
355
  export interface VectorLayer {
@@ -325,17 +375,8 @@ export type RasterMetadataBandStats = {
325
375
 
326
376
  /**
327
377
  * Quantiles by number of buckets.
328
- *
329
- * Example:
330
- * ```ts
331
- * {
332
- * // for 3 buckets, first 1/3 of items lies in range [min, 20], second 1/3 is in [20, 40], and last 1/3 is in [40, max]
333
- * 3: [20, 40],
334
- * 4: [20, 30, 50], for 4 buckets ...
335
- * }
336
- * ```
337
378
  */
338
- quantiles?: Record<number, number[]>;
379
+ quantiles?: QuantileStats;
339
380
 
340
381
  /**
341
382
  * Top values by number of values.