@carto/api-client 0.5.15-alpha.raster-1 → 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/build/api-client.cjs +212 -134
- package/build/api-client.cjs.map +1 -1
- package/build/api-client.d.cts +45 -17
- package/build/api-client.d.ts +45 -17
- package/build/api-client.js +211 -134
- package/build/api-client.js.map +1 -1
- package/package.json +1 -1
- package/src/fetch-map/index.ts +1 -0
- package/src/fetch-map/layer-map.ts +76 -18
- package/src/fetch-map/parse-map.ts +136 -126
- package/src/fetch-map/raster-layer.ts +6 -4
- package/src/fetch-map/types.ts +7 -7
- package/src/fetch-map/utils.ts +56 -0
- package/src/fetch-map/vec-expr-evaluator.ts +0 -12
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-
|
|
11
|
+
"version": "0.5.15-alpha.raster-3",
|
|
12
12
|
"license": "MIT",
|
|
13
13
|
"publishConfig": {
|
|
14
14
|
"access": "public"
|
package/src/fetch-map/index.ts
CHANGED
|
@@ -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 {
|
|
@@ -74,7 +75,21 @@ function identity<T>(v: T): T {
|
|
|
74
75
|
return v;
|
|
75
76
|
}
|
|
76
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
|
+
|
|
77
91
|
const UNKNOWN_COLOR = '#868d91';
|
|
92
|
+
const UNKNOWN_COLOR_RGB = hexToRGB(UNKNOWN_COLOR);
|
|
78
93
|
|
|
79
94
|
export const OPACITY_MAP: Record<string, string> = {
|
|
80
95
|
getFillColor: 'opacity',
|
|
@@ -318,11 +333,16 @@ function findAccessorKey(keys: string[], properties: any): string[] {
|
|
|
318
333
|
export function getColorAccessor(
|
|
319
334
|
{name, colorColumn}: VisualChannelField,
|
|
320
335
|
scaleType: ScaleType,
|
|
321
|
-
{aggregation, range}: {aggregation
|
|
336
|
+
{aggregation, range}: {aggregation?: string; range: ColorRange},
|
|
322
337
|
opacity: number | undefined,
|
|
323
338
|
data: TilejsonResult
|
|
324
|
-
): {
|
|
325
|
-
|
|
339
|
+
): {
|
|
340
|
+
accessor: any;
|
|
341
|
+
domain: number[] | string[];
|
|
342
|
+
scaleDomain: number[] | string[];
|
|
343
|
+
range: string[];
|
|
344
|
+
} {
|
|
345
|
+
const {scale, domain} = calculateLayerScale(
|
|
326
346
|
colorColumn || name,
|
|
327
347
|
scaleType,
|
|
328
348
|
range,
|
|
@@ -336,10 +356,15 @@ export function getColorAccessor(
|
|
|
336
356
|
accessorKeys = findAccessorKey(accessorKeys, properties);
|
|
337
357
|
}
|
|
338
358
|
const propertyValue = properties[accessorKeys[0]];
|
|
339
|
-
const
|
|
359
|
+
const [r, g, b] = scale(propertyValue);
|
|
340
360
|
return [r, g, b, propertyValue === null ? 0 : alpha];
|
|
341
361
|
};
|
|
342
|
-
return {
|
|
362
|
+
return {
|
|
363
|
+
accessor: normalizeAccessor(accessor, data),
|
|
364
|
+
scaleDomain: scale.domain(),
|
|
365
|
+
domain,
|
|
366
|
+
range: scale.range().map(rgbToHex),
|
|
367
|
+
};
|
|
343
368
|
}
|
|
344
369
|
|
|
345
370
|
export function calculateLayerScale(
|
|
@@ -347,29 +372,48 @@ export function calculateLayerScale(
|
|
|
347
372
|
scaleType: ScaleType,
|
|
348
373
|
range: ColorRange,
|
|
349
374
|
data: TilejsonResult
|
|
350
|
-
) {
|
|
375
|
+
): {scale: D3Scale; domain: string[] | number[]} {
|
|
351
376
|
let domain: string[] | number[] = [];
|
|
377
|
+
let scaleDomain: number[] | undefined;
|
|
352
378
|
let scaleColor: string[] = [];
|
|
379
|
+
const {colors} = range;
|
|
353
380
|
|
|
354
|
-
if (scaleType
|
|
355
|
-
|
|
381
|
+
if (scaleType === 'custom') {
|
|
382
|
+
if (range.uiCustomScaleType === 'logarithmic') {
|
|
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
|
+
});
|
|
356
390
|
|
|
357
|
-
|
|
391
|
+
scaleColor = colors;
|
|
392
|
+
} else if (range.colorMap) {
|
|
393
|
+
const {colorMap} = range;
|
|
358
394
|
colorMap.forEach(([value, color]) => {
|
|
359
395
|
(domain as string[]).push(value);
|
|
360
396
|
scaleColor.push(color);
|
|
361
397
|
});
|
|
362
|
-
} else {
|
|
363
|
-
domain = calculateDomain(data, name, scaleType, colors.length);
|
|
364
|
-
scaleColor = colors;
|
|
365
398
|
}
|
|
399
|
+
} else if (scaleType !== 'identity') {
|
|
400
|
+
domain = calculateDomain(data, name, scaleType, colors.length);
|
|
401
|
+
scaleColor = colors;
|
|
366
402
|
|
|
367
403
|
if (scaleType === 'ordinal') {
|
|
368
404
|
domain = domain.slice(0, scaleColor.length);
|
|
369
405
|
}
|
|
370
406
|
}
|
|
371
407
|
|
|
372
|
-
return
|
|
408
|
+
return {
|
|
409
|
+
scale: createColorScale(
|
|
410
|
+
scaleType,
|
|
411
|
+
scaleDomain || domain,
|
|
412
|
+
scaleColor.map(hexToRGB),
|
|
413
|
+
UNKNOWN_COLOR_RGB
|
|
414
|
+
),
|
|
415
|
+
domain,
|
|
416
|
+
};
|
|
373
417
|
}
|
|
374
418
|
|
|
375
419
|
export function createColorScale<T>(
|
|
@@ -457,13 +501,22 @@ export function getSizeAccessor(
|
|
|
457
501
|
{name}: VisualChannelField,
|
|
458
502
|
scaleType: ScaleType | undefined,
|
|
459
503
|
aggregation: string | null | undefined,
|
|
460
|
-
range:
|
|
504
|
+
range: number[] | undefined,
|
|
461
505
|
data: TilejsonResult
|
|
462
|
-
): {
|
|
506
|
+
): {
|
|
507
|
+
accessor: any;
|
|
508
|
+
domain: number[];
|
|
509
|
+
scaleDomain: number[];
|
|
510
|
+
range: number[] | undefined;
|
|
511
|
+
} {
|
|
463
512
|
const scale = scaleType ? SCALE_FUNCS[scaleType]() : identity;
|
|
464
|
-
|
|
513
|
+
let domain: number[] = [];
|
|
514
|
+
if (scaleType && range) {
|
|
465
515
|
if (aggregation !== AggregationTypes.Count) {
|
|
466
|
-
|
|
516
|
+
domain = calculateDomain(data, name, scaleType) as number[];
|
|
517
|
+
(scale as D3Scale).domain(domain);
|
|
518
|
+
} else {
|
|
519
|
+
domain = (scale as D3Scale).domain();
|
|
467
520
|
}
|
|
468
521
|
(scale as D3Scale).range(range);
|
|
469
522
|
}
|
|
@@ -476,7 +529,12 @@ export function getSizeAccessor(
|
|
|
476
529
|
const propertyValue = properties[accessorKeys[0]];
|
|
477
530
|
return scale(propertyValue);
|
|
478
531
|
};
|
|
479
|
-
return {
|
|
532
|
+
return {
|
|
533
|
+
accessor: normalizeAccessor(accessor, data),
|
|
534
|
+
domain,
|
|
535
|
+
scaleDomain: domain,
|
|
536
|
+
range,
|
|
537
|
+
};
|
|
480
538
|
}
|
|
481
539
|
|
|
482
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
|
-
|
|
45
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
324
|
-
|
|
325
|
-
const {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
{
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
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
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
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
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
const {
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
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
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
)
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
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
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
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
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
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) {
|
|
@@ -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
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
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) || [];
|
package/src/fetch-map/types.ts
CHANGED
|
@@ -63,7 +63,7 @@ export type VisConfig = {
|
|
|
63
63
|
opacity?: number;
|
|
64
64
|
enable3d?: boolean;
|
|
65
65
|
|
|
66
|
-
colorAggregation?:
|
|
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?:
|
|
77
|
-
sizeRange?:
|
|
76
|
+
sizeAggregation?: string;
|
|
77
|
+
sizeRange?: number[];
|
|
78
78
|
|
|
79
|
-
strokeColorAggregation?:
|
|
79
|
+
strokeColorAggregation?: string;
|
|
80
80
|
strokeOpacity?: number;
|
|
81
81
|
strokeColorRange?: ColorRange;
|
|
82
82
|
|
|
83
|
-
heightRange?:
|
|
84
|
-
heightAggregation?:
|
|
83
|
+
heightRange?: number[];
|
|
84
|
+
heightAggregation?: string;
|
|
85
85
|
|
|
86
|
-
weightAggregation?:
|
|
86
|
+
weightAggregation?: string;
|
|
87
87
|
|
|
88
88
|
// type = clusterTile
|
|
89
89
|
clusterLevel?: number;
|
package/src/fetch-map/utils.ts
CHANGED
|
@@ -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
|