@carto/api-client 0.4.5 → 0.4.6-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/build/api-client.cjs +2179 -216
- package/build/api-client.cjs.map +1 -1
- package/build/api-client.modern.js +2061 -226
- package/build/api-client.modern.js.map +1 -1
- package/build/constants.d.ts +22 -0
- package/build/filters/Filter.d.ts +13 -0
- package/build/filters/FilterTypes.d.ts +3 -0
- package/build/filters/geosjonFeatures.d.ts +8 -0
- package/build/filters/index.d.ts +6 -0
- package/build/filters/tileFeatures.d.ts +20 -0
- package/build/filters/tileFeaturesGeometries.d.ts +13 -0
- package/build/filters/tileFeaturesSpatialIndex.d.ts +10 -0
- package/build/index.d.ts +4 -0
- package/build/models/index.d.ts +1 -1
- package/build/operations/aggregation.d.ts +8 -0
- package/build/operations/applySorting.d.ts +20 -0
- package/build/operations/groupBy.d.ts +15 -0
- package/build/operations/groupByDate.d.ts +11 -0
- package/build/operations/histogram.d.ts +13 -0
- package/build/operations/index.d.ts +6 -0
- package/build/operations/scatterPlot.d.ts +14 -0
- package/build/sources/h3-tileset-source.d.ts +2 -1
- package/build/sources/index.d.ts +1 -1
- package/build/sources/quadbin-tileset-source.d.ts +2 -1
- package/build/sources/vector-tileset-source.d.ts +2 -1
- package/build/types-internal.d.ts +4 -0
- package/build/types.d.ts +61 -1
- package/build/utils/dateUtils.d.ts +10 -0
- package/build/utils/getTileFormat.d.ts +3 -0
- package/build/utils/makeIntervalComplete.d.ts +2 -0
- package/build/utils/transformTileCoordsToWGS84.d.ts +8 -0
- package/build/utils/transformToTileCoords.d.ts +9 -0
- package/build/widget-sources/index.d.ts +3 -1
- package/build/widget-sources/types.d.ts +31 -22
- package/build/widget-sources/widget-query-source.d.ts +2 -2
- package/build/widget-sources/widget-remote-source.d.ts +18 -0
- package/build/widget-sources/{widget-base-source.d.ts → widget-source.d.ts} +13 -38
- package/build/widget-sources/widget-table-source.d.ts +2 -2
- package/build/widget-sources/widget-tileset-source.d.ts +76 -0
- package/package.json +10 -3
- package/src/constants.ts +25 -0
- package/src/filters/Filter.ts +169 -0
- package/src/filters/FilterTypes.ts +109 -0
- package/src/filters/geosjonFeatures.ts +32 -0
- package/src/filters/index.ts +6 -0
- package/src/filters/tileFeatures.ts +56 -0
- package/src/filters/tileFeaturesGeometries.ts +444 -0
- package/src/filters/tileFeaturesSpatialIndex.ts +119 -0
- package/src/index.ts +6 -0
- package/src/models/index.ts +1 -1
- package/src/operations/aggregation.ts +154 -0
- package/src/operations/applySorting.ts +109 -0
- package/src/operations/groupBy.ts +59 -0
- package/src/operations/groupByDate.ts +98 -0
- package/src/operations/histogram.ts +66 -0
- package/src/operations/index.ts +6 -0
- package/src/operations/scatterPlot.ts +50 -0
- package/src/sources/h3-tileset-source.ts +18 -6
- package/src/sources/index.ts +1 -1
- package/src/sources/quadbin-tileset-source.ts +18 -6
- package/src/sources/raster-source.ts +1 -0
- package/src/sources/vector-query-source.ts +5 -2
- package/src/sources/vector-table-source.ts +5 -2
- package/src/sources/vector-tileset-source.ts +19 -6
- package/src/types-internal.ts +6 -0
- package/src/types.ts +60 -2
- package/src/utils/dateUtils.ts +28 -0
- package/src/utils/getTileFormat.ts +9 -0
- package/src/utils/makeIntervalComplete.ts +17 -0
- package/src/utils/transformTileCoordsToWGS84.ts +77 -0
- package/src/utils/transformToTileCoords.ts +85 -0
- package/src/widget-sources/index.ts +3 -1
- package/src/widget-sources/types.ts +32 -22
- package/src/widget-sources/widget-query-source.ts +6 -3
- package/src/widget-sources/{widget-base-source.ts → widget-remote-source.ts} +12 -147
- package/src/widget-sources/widget-source.ts +160 -0
- package/src/widget-sources/widget-table-source.ts +6 -3
- package/src/widget-sources/widget-tileset-source.ts +407 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import {AggregationType} from '../types';
|
|
2
|
+
import {FeatureData} from '../types-internal';
|
|
3
|
+
|
|
4
|
+
/** @internalRemarks Source: @carto/react-core */
|
|
5
|
+
export type AggregationFunction = (
|
|
6
|
+
values: unknown[] | FeatureData[],
|
|
7
|
+
keys?: string[] | string,
|
|
8
|
+
joinOperation?: AggregationType
|
|
9
|
+
) => number;
|
|
10
|
+
|
|
11
|
+
/** @internalRemarks Source: @carto/react-core */
|
|
12
|
+
export const aggregationFunctions: Record<
|
|
13
|
+
Exclude<AggregationType, 'custom'>,
|
|
14
|
+
AggregationFunction
|
|
15
|
+
> = {
|
|
16
|
+
count: (values) => values.length,
|
|
17
|
+
min: (...args) => applyAggregationFunction(min, ...args),
|
|
18
|
+
max: (...args) => applyAggregationFunction(max, ...args),
|
|
19
|
+
sum: (...args) => applyAggregationFunction(sum, ...args),
|
|
20
|
+
avg: (...args) => applyAggregationFunction(avg, ...args),
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/** @internalRemarks Source: @carto/react-core */
|
|
24
|
+
export function aggregate(
|
|
25
|
+
feature: FeatureData,
|
|
26
|
+
keys?: string[],
|
|
27
|
+
operation?: AggregationType
|
|
28
|
+
): unknown {
|
|
29
|
+
if (!keys?.length) {
|
|
30
|
+
throw new Error('Cannot aggregate a feature without having keys');
|
|
31
|
+
} else if (keys.length === 1) {
|
|
32
|
+
const value = feature[keys[0]];
|
|
33
|
+
return isPotentiallyValidNumber(value) ? Number(value) : value;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const aggregationFn =
|
|
37
|
+
aggregationFunctions[operation as Exclude<AggregationType, 'custom'>];
|
|
38
|
+
|
|
39
|
+
if (!aggregationFn) {
|
|
40
|
+
throw new Error(`${operation} isn't a valid aggregation function`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return aggregationFn(
|
|
44
|
+
keys.map((column) => {
|
|
45
|
+
const value = feature[column];
|
|
46
|
+
return isPotentiallyValidNumber(value) ? Number(value) : value;
|
|
47
|
+
})
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/*
|
|
52
|
+
* Forced casting to Number (just of non empty strings) allows to work-around
|
|
53
|
+
* some specific situations, where a big numeric field is transformed into a string when generating the tileset(eg.PG)
|
|
54
|
+
*/
|
|
55
|
+
function isPotentiallyValidNumber(value: unknown): boolean {
|
|
56
|
+
return typeof value === 'string' && value.trim().length > 0;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const applyAggregationFunction = (
|
|
60
|
+
aggFn: AggregationFunction,
|
|
61
|
+
values: unknown[] | FeatureData[],
|
|
62
|
+
keys?: string[] | string,
|
|
63
|
+
operation?: AggregationType
|
|
64
|
+
) => {
|
|
65
|
+
const normalizedKeys = normalizeKeys(keys);
|
|
66
|
+
const elements =
|
|
67
|
+
(normalizedKeys?.length || 0) <= 1
|
|
68
|
+
? filterFalsyElements(values as unknown[], normalizedKeys || [])
|
|
69
|
+
: values;
|
|
70
|
+
return aggFn(elements, keys, operation);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
function filterFalsyElements(
|
|
74
|
+
values: unknown[] | FeatureData[],
|
|
75
|
+
keys: string[]
|
|
76
|
+
) {
|
|
77
|
+
const filterFn = (value: unknown) => value !== null && value !== undefined;
|
|
78
|
+
|
|
79
|
+
if (!keys?.length) {
|
|
80
|
+
return values.filter(filterFn);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return (values as FeatureData[]).filter((v) => filterFn(v[keys[0]]));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Aggregation functions
|
|
87
|
+
function avg(
|
|
88
|
+
values: unknown[] | FeatureData[],
|
|
89
|
+
keys?: string[] | string,
|
|
90
|
+
joinOperation?: AggregationType
|
|
91
|
+
): number {
|
|
92
|
+
return sum(values, keys, joinOperation) / (values.length || 1);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function sum(
|
|
96
|
+
values: unknown[] | FeatureData[],
|
|
97
|
+
keys?: string[] | string,
|
|
98
|
+
joinOperation?: AggregationType
|
|
99
|
+
): number {
|
|
100
|
+
const normalizedKeys = normalizeKeys(keys);
|
|
101
|
+
|
|
102
|
+
if (normalizedKeys) {
|
|
103
|
+
return (values as FeatureData[]).reduce(
|
|
104
|
+
(a, b) => a + (aggregate(b, normalizedKeys, joinOperation) as number),
|
|
105
|
+
0
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return values.reduce((a: number, b: unknown) => a + (b as number), 0);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function min(
|
|
113
|
+
values: unknown[] | FeatureData[],
|
|
114
|
+
keys?: string[] | string,
|
|
115
|
+
joinOperation?: AggregationType
|
|
116
|
+
): number {
|
|
117
|
+
const normalizedKeys = normalizeKeys(keys);
|
|
118
|
+
if (normalizedKeys) {
|
|
119
|
+
return (values as FeatureData[]).reduce(
|
|
120
|
+
(a, b) =>
|
|
121
|
+
Math.min(a, aggregate(b, normalizedKeys, joinOperation) as number),
|
|
122
|
+
Infinity
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
return Math.min(...(values as number[]));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function max(
|
|
129
|
+
values: unknown[] | FeatureData[],
|
|
130
|
+
keys?: string[] | string,
|
|
131
|
+
joinOperation?: AggregationType
|
|
132
|
+
): number {
|
|
133
|
+
const normalizedKeys = normalizeKeys(keys);
|
|
134
|
+
if (normalizedKeys) {
|
|
135
|
+
return (values as FeatureData[]).reduce(
|
|
136
|
+
(a, b) =>
|
|
137
|
+
Math.max(a, aggregate(b, normalizedKeys, joinOperation) as number),
|
|
138
|
+
-Infinity
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
return Math.max(...(values as number[]));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Aux
|
|
145
|
+
|
|
146
|
+
// Keys can come as a string (one column) or a strings array (multiple column)
|
|
147
|
+
// Use always an array to make the code easier
|
|
148
|
+
function normalizeKeys(keys: unknown): string[] | undefined {
|
|
149
|
+
return Array.isArray(keys)
|
|
150
|
+
? keys
|
|
151
|
+
: typeof keys === 'string'
|
|
152
|
+
? [keys]
|
|
153
|
+
: undefined;
|
|
154
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import {firstBy} from 'thenby';
|
|
2
|
+
import {SortDirection} from '../types';
|
|
3
|
+
import {FeatureData} from '../types-internal';
|
|
4
|
+
|
|
5
|
+
// TODO(cleanup): Could this be simplified?
|
|
6
|
+
type SortColumns = string | string[] | object[];
|
|
7
|
+
|
|
8
|
+
interface SortOptions {
|
|
9
|
+
sortBy?: SortColumns;
|
|
10
|
+
sortByDirection?: SortDirection;
|
|
11
|
+
sortByColumnType?: 'number' | 'string' | 'date';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Apply sort structure to a collection of features
|
|
16
|
+
* @param features
|
|
17
|
+
* @param [sortOptions]
|
|
18
|
+
* @param [sortOptions.sortBy] - One or more columns to sort by
|
|
19
|
+
* @param [sortOptions.sortByDirection] - Direction by the columns will be sorted
|
|
20
|
+
* @param [sortOptions.sortByColumnType] - Column type
|
|
21
|
+
* @internal
|
|
22
|
+
* @internalRemarks Source: @carto/react-core
|
|
23
|
+
*/
|
|
24
|
+
export function applySorting(
|
|
25
|
+
features: FeatureData[],
|
|
26
|
+
{
|
|
27
|
+
sortBy,
|
|
28
|
+
sortByDirection = 'asc',
|
|
29
|
+
sortByColumnType = 'string',
|
|
30
|
+
}: SortOptions = {}
|
|
31
|
+
): FeatureData[] {
|
|
32
|
+
// If sortBy is undefined, pass all features
|
|
33
|
+
if (sortBy === undefined) {
|
|
34
|
+
return features;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// sortOptions exists, but are bad formatted
|
|
38
|
+
const isValidSortBy =
|
|
39
|
+
(Array.isArray(sortBy) && sortBy.length) || // sortBy can be an array of columns
|
|
40
|
+
typeof sortBy === 'string'; // or just one column
|
|
41
|
+
|
|
42
|
+
if (!isValidSortBy) {
|
|
43
|
+
throw new Error('Sorting options are bad formatted');
|
|
44
|
+
}
|
|
45
|
+
const sortFn = createSortFn({
|
|
46
|
+
sortBy,
|
|
47
|
+
sortByDirection,
|
|
48
|
+
sortByColumnType: sortByColumnType || 'string',
|
|
49
|
+
});
|
|
50
|
+
return features.sort(sortFn);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Aux
|
|
54
|
+
function createSortFn({
|
|
55
|
+
sortBy,
|
|
56
|
+
sortByDirection,
|
|
57
|
+
sortByColumnType,
|
|
58
|
+
}: Required<SortOptions>) {
|
|
59
|
+
const [firstSortOption, ...othersSortOptions] = normalizeSortByOptions({
|
|
60
|
+
sortBy,
|
|
61
|
+
sortByDirection,
|
|
62
|
+
sortByColumnType,
|
|
63
|
+
}) as Parameters<typeof firstBy>[];
|
|
64
|
+
|
|
65
|
+
let sortFn = firstBy(...firstSortOption);
|
|
66
|
+
for (let sortOptions of othersSortOptions) {
|
|
67
|
+
sortFn = sortFn.thenBy(...sortOptions);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return sortFn;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function normalizeSortByOptions({
|
|
74
|
+
sortBy,
|
|
75
|
+
sortByDirection,
|
|
76
|
+
sortByColumnType,
|
|
77
|
+
}: Required<SortOptions>) {
|
|
78
|
+
const numberFormat = sortByColumnType === 'number' && {
|
|
79
|
+
cmp: (a: number, b: number) => a - b,
|
|
80
|
+
};
|
|
81
|
+
if (!Array.isArray(sortBy)) {
|
|
82
|
+
sortBy = [sortBy];
|
|
83
|
+
}
|
|
84
|
+
return sortBy.map((sortByEl) => {
|
|
85
|
+
// sortByEl is 'column'
|
|
86
|
+
if (typeof sortByEl === 'string') {
|
|
87
|
+
return [sortByEl, {direction: sortByDirection, ...numberFormat}];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (Array.isArray(sortByEl)) {
|
|
91
|
+
// sortBy is ['column']
|
|
92
|
+
if (sortByEl[1] === undefined) {
|
|
93
|
+
return [sortByEl, {direction: sortByDirection, ...numberFormat}];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// sortBy is ['column', { ... }]
|
|
97
|
+
if (typeof sortByEl[1] === 'object') {
|
|
98
|
+
const othersSortOptions = numberFormat
|
|
99
|
+
? {...numberFormat, ...sortByEl[1]}
|
|
100
|
+
: sortByEl[1];
|
|
101
|
+
return [
|
|
102
|
+
sortByEl[0],
|
|
103
|
+
{direction: sortByDirection, ...othersSortOptions},
|
|
104
|
+
];
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return sortByEl;
|
|
108
|
+
});
|
|
109
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import {aggregationFunctions, aggregate} from './aggregation.js';
|
|
2
|
+
import {AggregationType} from '../types';
|
|
3
|
+
import {FeatureData} from '../types-internal';
|
|
4
|
+
|
|
5
|
+
/** @internalRemarks Source: @carto/react-core */
|
|
6
|
+
export type GroupByFeature = {
|
|
7
|
+
name: string;
|
|
8
|
+
value: number;
|
|
9
|
+
}[];
|
|
10
|
+
|
|
11
|
+
/** @internalRemarks Source: @carto/react-core */
|
|
12
|
+
export function groupValuesByColumn({
|
|
13
|
+
data,
|
|
14
|
+
valuesColumns,
|
|
15
|
+
joinOperation,
|
|
16
|
+
keysColumn,
|
|
17
|
+
operation,
|
|
18
|
+
}: {
|
|
19
|
+
data: FeatureData[];
|
|
20
|
+
valuesColumns?: string[];
|
|
21
|
+
joinOperation?: AggregationType;
|
|
22
|
+
keysColumn: string;
|
|
23
|
+
operation: AggregationType;
|
|
24
|
+
}): GroupByFeature | null {
|
|
25
|
+
if (Array.isArray(data) && data.length === 0) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
const groups = data.reduce((accumulator, item) => {
|
|
29
|
+
const group = item[keysColumn];
|
|
30
|
+
|
|
31
|
+
const values = accumulator.get(group) || [];
|
|
32
|
+
accumulator.set(group, values);
|
|
33
|
+
|
|
34
|
+
const aggregatedValue = aggregate(item, valuesColumns, joinOperation);
|
|
35
|
+
|
|
36
|
+
const isValid =
|
|
37
|
+
(operation === 'count' ? true : aggregatedValue !== null) &&
|
|
38
|
+
aggregatedValue !== undefined;
|
|
39
|
+
|
|
40
|
+
if (isValid) {
|
|
41
|
+
values.push(aggregatedValue);
|
|
42
|
+
accumulator.set(group, values);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return accumulator;
|
|
46
|
+
}, new Map()); // We use a map to be able to maintain the type in the key value
|
|
47
|
+
|
|
48
|
+
const targetOperation =
|
|
49
|
+
aggregationFunctions[operation as Exclude<AggregationType, 'custom'>];
|
|
50
|
+
|
|
51
|
+
if (targetOperation) {
|
|
52
|
+
return Array.from(groups).map(([name, value]) => ({
|
|
53
|
+
name,
|
|
54
|
+
value: targetOperation(value),
|
|
55
|
+
}));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import {AggregationType, GroupDateType} from '../types.js';
|
|
2
|
+
import {getUTCMonday} from '../utils/dateUtils.js';
|
|
3
|
+
import {aggregate, aggregationFunctions} from './aggregation.js';
|
|
4
|
+
import {GroupByFeature} from './groupBy.js';
|
|
5
|
+
|
|
6
|
+
const GROUP_KEY_FN_MAPPING: Record<GroupDateType, (date: Date) => number> = {
|
|
7
|
+
year: (date: Date) => Date.UTC(date.getUTCFullYear()),
|
|
8
|
+
month: (date: Date) => Date.UTC(date.getUTCFullYear(), date.getUTCMonth()),
|
|
9
|
+
week: (date: Date) => getUTCMonday(date),
|
|
10
|
+
day: (date: Date) =>
|
|
11
|
+
Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()),
|
|
12
|
+
hour: (date: Date) =>
|
|
13
|
+
Date.UTC(
|
|
14
|
+
date.getUTCFullYear(),
|
|
15
|
+
date.getUTCMonth(),
|
|
16
|
+
date.getUTCDate(),
|
|
17
|
+
date.getUTCHours()
|
|
18
|
+
),
|
|
19
|
+
minute: (date: Date) =>
|
|
20
|
+
Date.UTC(
|
|
21
|
+
date.getUTCFullYear(),
|
|
22
|
+
date.getUTCMonth(),
|
|
23
|
+
date.getUTCDate(),
|
|
24
|
+
date.getUTCHours(),
|
|
25
|
+
date.getUTCMinutes()
|
|
26
|
+
),
|
|
27
|
+
second: (date: Date) =>
|
|
28
|
+
Date.UTC(
|
|
29
|
+
date.getUTCFullYear(),
|
|
30
|
+
date.getUTCMonth(),
|
|
31
|
+
date.getUTCDate(),
|
|
32
|
+
date.getUTCHours(),
|
|
33
|
+
date.getUTCMinutes(),
|
|
34
|
+
date.getUTCSeconds()
|
|
35
|
+
),
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/** @internalRemarks Source: @carto/react-core */
|
|
39
|
+
export function groupValuesByDateColumn({
|
|
40
|
+
data,
|
|
41
|
+
valuesColumns,
|
|
42
|
+
joinOperation,
|
|
43
|
+
keysColumn,
|
|
44
|
+
groupType,
|
|
45
|
+
operation,
|
|
46
|
+
}: {
|
|
47
|
+
data: Record<string, unknown>[];
|
|
48
|
+
valuesColumns?: string[];
|
|
49
|
+
joinOperation?: Exclude<AggregationType, 'custom'>;
|
|
50
|
+
keysColumn: string;
|
|
51
|
+
groupType: GroupDateType;
|
|
52
|
+
operation?: Exclude<AggregationType, 'custom'>;
|
|
53
|
+
}): GroupByFeature | null {
|
|
54
|
+
if (Array.isArray(data) && data.length === 0) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const groupKeyFn = GROUP_KEY_FN_MAPPING[groupType];
|
|
59
|
+
|
|
60
|
+
if (!groupKeyFn) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const groups = data.reduce((acc, item) => {
|
|
65
|
+
const value = item[keysColumn];
|
|
66
|
+
const formattedValue = new Date(value as number);
|
|
67
|
+
const groupKey = groupKeyFn(formattedValue);
|
|
68
|
+
|
|
69
|
+
if (!isNaN(groupKey)) {
|
|
70
|
+
let groupedValues = acc.get(groupKey);
|
|
71
|
+
if (!groupedValues) {
|
|
72
|
+
groupedValues = [];
|
|
73
|
+
acc.set(groupKey, groupedValues);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const aggregatedValue = aggregate(item, valuesColumns, joinOperation);
|
|
77
|
+
|
|
78
|
+
const isValid = aggregatedValue !== null && aggregatedValue !== undefined;
|
|
79
|
+
|
|
80
|
+
if (isValid) {
|
|
81
|
+
groupedValues.push(aggregatedValue);
|
|
82
|
+
acc.set(groupKey, groupedValues);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return acc;
|
|
87
|
+
}, new Map());
|
|
88
|
+
|
|
89
|
+
const targetOperation =
|
|
90
|
+
aggregationFunctions[operation as Exclude<AggregationType, 'custom'>];
|
|
91
|
+
|
|
92
|
+
return [...groups.entries()]
|
|
93
|
+
.map(([name, value]) => ({
|
|
94
|
+
name,
|
|
95
|
+
value: targetOperation(value),
|
|
96
|
+
}))
|
|
97
|
+
.sort((a, b) => a.name - b.name);
|
|
98
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import {aggregate, aggregationFunctions} from './aggregation';
|
|
2
|
+
import {AggregationType} from '../types';
|
|
3
|
+
import {FeatureData} from '../types-internal';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Histogram computation.
|
|
7
|
+
* @internalRemarks Source: @carto/react-core
|
|
8
|
+
*/
|
|
9
|
+
export function histogram({
|
|
10
|
+
data,
|
|
11
|
+
valuesColumns,
|
|
12
|
+
joinOperation,
|
|
13
|
+
ticks,
|
|
14
|
+
operation,
|
|
15
|
+
}: {
|
|
16
|
+
data: FeatureData[];
|
|
17
|
+
valuesColumns?: string[];
|
|
18
|
+
joinOperation?: Exclude<AggregationType, 'custom'>;
|
|
19
|
+
ticks: number[];
|
|
20
|
+
operation: Exclude<AggregationType, 'custom'>;
|
|
21
|
+
}): number[] {
|
|
22
|
+
if (Array.isArray(data) && data.length === 0) {
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const binsContainer = [Number.MIN_SAFE_INTEGER, ...ticks].map(
|
|
27
|
+
(tick, index, arr) => ({
|
|
28
|
+
bin: index,
|
|
29
|
+
start: tick,
|
|
30
|
+
end: index === arr.length - 1 ? Number.MAX_SAFE_INTEGER : arr[index + 1],
|
|
31
|
+
values: [] as number[],
|
|
32
|
+
})
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
data.forEach((feature) => {
|
|
36
|
+
const featureValue = aggregate(
|
|
37
|
+
feature,
|
|
38
|
+
valuesColumns,
|
|
39
|
+
joinOperation
|
|
40
|
+
) as number;
|
|
41
|
+
|
|
42
|
+
const isValid = featureValue !== null && featureValue !== undefined;
|
|
43
|
+
|
|
44
|
+
if (!isValid) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const binContainer = binsContainer.find(
|
|
49
|
+
(bin) => bin.start <= featureValue && bin.end > featureValue
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
if (!binContainer) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
binContainer.values.push(featureValue);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const targetOperation = aggregationFunctions[operation];
|
|
60
|
+
const transformedBins = binsContainer.map(
|
|
61
|
+
(binContainer) => binContainer.values
|
|
62
|
+
);
|
|
63
|
+
return transformedBins.map((values) =>
|
|
64
|
+
values.length ? targetOperation(values) : 0
|
|
65
|
+
);
|
|
66
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {aggregate} from './aggregation';
|
|
2
|
+
import {FeatureData} from '../types-internal';
|
|
3
|
+
import {AggregationType} from '../types';
|
|
4
|
+
|
|
5
|
+
export type ScatterPlotFeature = [number, number][];
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Filters invalid features and formats data.
|
|
9
|
+
* @internalRemarks Source: @carto/react-core
|
|
10
|
+
*/
|
|
11
|
+
export function scatterPlot({
|
|
12
|
+
data,
|
|
13
|
+
xAxisColumns,
|
|
14
|
+
xAxisJoinOperation,
|
|
15
|
+
yAxisColumns,
|
|
16
|
+
yAxisJoinOperation,
|
|
17
|
+
}: {
|
|
18
|
+
data: FeatureData[];
|
|
19
|
+
xAxisColumns: string[];
|
|
20
|
+
xAxisJoinOperation?: AggregationType;
|
|
21
|
+
yAxisColumns: string[];
|
|
22
|
+
yAxisJoinOperation?: AggregationType;
|
|
23
|
+
}): ScatterPlotFeature {
|
|
24
|
+
return data.reduce(
|
|
25
|
+
(acc, feature) => {
|
|
26
|
+
const xValue = aggregate(
|
|
27
|
+
feature,
|
|
28
|
+
xAxisColumns,
|
|
29
|
+
xAxisJoinOperation
|
|
30
|
+
) as number;
|
|
31
|
+
|
|
32
|
+
const xIsValid = xValue !== null && xValue !== undefined;
|
|
33
|
+
|
|
34
|
+
const yValue = aggregate(
|
|
35
|
+
feature,
|
|
36
|
+
yAxisColumns,
|
|
37
|
+
yAxisJoinOperation
|
|
38
|
+
) as number;
|
|
39
|
+
|
|
40
|
+
const yIsValid = yValue !== null && yValue !== undefined;
|
|
41
|
+
|
|
42
|
+
if (xIsValid && yIsValid) {
|
|
43
|
+
acc.push([xValue, yValue]);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return acc;
|
|
47
|
+
},
|
|
48
|
+
[] as [number, number][]
|
|
49
|
+
);
|
|
50
|
+
}
|
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
|
+
import {getTileFormat} from '../utils/getTileFormat';
|
|
6
|
+
import {
|
|
7
|
+
WidgetTilesetSource,
|
|
8
|
+
WidgetTilesetSourceResult,
|
|
9
|
+
} from '../widget-sources';
|
|
5
10
|
import {baseSource} from './base-source';
|
|
6
11
|
import type {
|
|
7
12
|
SourceOptions,
|
|
@@ -12,17 +17,24 @@ import type {
|
|
|
12
17
|
export type H3TilesetSourceOptions = SourceOptions & TilesetSourceOptions;
|
|
13
18
|
type UrlParameters = {name: string};
|
|
14
19
|
|
|
15
|
-
export type H3TilesetSourceResponse = TilejsonResult
|
|
20
|
+
export type H3TilesetSourceResponse = TilejsonResult &
|
|
21
|
+
WidgetTilesetSourceResult;
|
|
16
22
|
|
|
17
23
|
export const h3TilesetSource = async function (
|
|
18
24
|
options: H3TilesetSourceOptions
|
|
19
25
|
): Promise<H3TilesetSourceResponse> {
|
|
20
|
-
const {tableName} = options;
|
|
26
|
+
const {tableName, spatialDataColumn = 'h3'} = options;
|
|
21
27
|
const urlParameters: UrlParameters = {name: tableName};
|
|
22
28
|
|
|
23
|
-
return baseSource<UrlParameters>(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
return baseSource<UrlParameters>('tileset', options, urlParameters).then(
|
|
30
|
+
(result) => ({
|
|
31
|
+
...(result as TilejsonResult),
|
|
32
|
+
widgetSource: new WidgetTilesetSource({
|
|
33
|
+
...options,
|
|
34
|
+
tileFormat: getTileFormat(result as TilejsonResult),
|
|
35
|
+
spatialDataColumn,
|
|
36
|
+
spatialDataType: 'h3',
|
|
37
|
+
}),
|
|
38
|
+
})
|
|
27
39
|
) as Promise<H3TilesetSourceResponse>;
|
|
28
40
|
};
|
package/src/sources/index.ts
CHANGED
|
@@ -52,7 +52,7 @@ export type {
|
|
|
52
52
|
} from './h3-tileset-source';
|
|
53
53
|
|
|
54
54
|
export {rasterSource} from './raster-source';
|
|
55
|
-
export type {RasterSourceOptions
|
|
55
|
+
export type {RasterSourceOptions} from './raster-source';
|
|
56
56
|
|
|
57
57
|
export {quadbinQuerySource} from './quadbin-query-source';
|
|
58
58
|
export type {
|
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
|
+
import {getTileFormat} from '../utils/getTileFormat';
|
|
6
|
+
import {
|
|
7
|
+
WidgetTilesetSource,
|
|
8
|
+
WidgetTilesetSourceResult,
|
|
9
|
+
} from '../widget-sources';
|
|
5
10
|
import {baseSource} from './base-source';
|
|
6
11
|
import type {
|
|
7
12
|
SourceOptions,
|
|
@@ -12,17 +17,24 @@ import type {
|
|
|
12
17
|
export type QuadbinTilesetSourceOptions = SourceOptions & TilesetSourceOptions;
|
|
13
18
|
type UrlParameters = {name: string};
|
|
14
19
|
|
|
15
|
-
export type QuadbinTilesetSourceResponse = TilejsonResult
|
|
20
|
+
export type QuadbinTilesetSourceResponse = TilejsonResult &
|
|
21
|
+
WidgetTilesetSourceResult;
|
|
16
22
|
|
|
17
23
|
export const quadbinTilesetSource = async function (
|
|
18
24
|
options: QuadbinTilesetSourceOptions
|
|
19
25
|
): Promise<QuadbinTilesetSourceResponse> {
|
|
20
|
-
const {tableName} = options;
|
|
26
|
+
const {tableName, spatialDataColumn = 'quadbin'} = options;
|
|
21
27
|
const urlParameters: UrlParameters = {name: tableName};
|
|
22
28
|
|
|
23
|
-
return baseSource<UrlParameters>(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
return baseSource<UrlParameters>('tileset', options, urlParameters).then(
|
|
30
|
+
(result) => ({
|
|
31
|
+
...(result as TilejsonResult),
|
|
32
|
+
widgetSource: new WidgetTilesetSource({
|
|
33
|
+
...options,
|
|
34
|
+
tileFormat: getTileFormat(result as TilejsonResult),
|
|
35
|
+
spatialDataColumn,
|
|
36
|
+
spatialDataType: 'quadbin',
|
|
37
|
+
}),
|
|
38
|
+
})
|
|
27
39
|
) as Promise<QuadbinTilesetSourceResponse>;
|
|
28
40
|
};
|
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
5
|
/* eslint-disable camelcase */
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
DEFAULT_GEO_COLUMN,
|
|
8
|
+
DEFAULT_TILE_RESOLUTION,
|
|
9
|
+
} from '../constants-internal.js';
|
|
7
10
|
import {
|
|
8
11
|
WidgetQuerySource,
|
|
9
12
|
WidgetQuerySourceResult,
|
|
@@ -43,7 +46,7 @@ export const vectorQuerySource = async function (
|
|
|
43
46
|
const {
|
|
44
47
|
columns,
|
|
45
48
|
filters,
|
|
46
|
-
spatialDataColumn =
|
|
49
|
+
spatialDataColumn = DEFAULT_GEO_COLUMN,
|
|
47
50
|
sqlQuery,
|
|
48
51
|
tileResolution = DEFAULT_TILE_RESOLUTION,
|
|
49
52
|
queryParameters,
|
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
5
|
/* eslint-disable camelcase */
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
DEFAULT_GEO_COLUMN,
|
|
8
|
+
DEFAULT_TILE_RESOLUTION,
|
|
9
|
+
} from '../constants-internal.js';
|
|
7
10
|
import {
|
|
8
11
|
WidgetTableSource,
|
|
9
12
|
WidgetTableSourceResult,
|
|
@@ -42,7 +45,7 @@ export const vectorTableSource = async function (
|
|
|
42
45
|
const {
|
|
43
46
|
columns,
|
|
44
47
|
filters,
|
|
45
|
-
spatialDataColumn =
|
|
48
|
+
spatialDataColumn = DEFAULT_GEO_COLUMN,
|
|
46
49
|
tableName,
|
|
47
50
|
tileResolution = DEFAULT_TILE_RESOLUTION,
|
|
48
51
|
aggregationExp,
|