@carto/api-client 0.5.0-alpha.2 → 0.5.0-alpha.4
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/CHANGELOG.md +4 -0
- package/build/api/carto-api-error.d.ts +1 -1
- package/build/api/query.d.ts +1 -1
- package/build/api/request-with-parameters.d.ts +2 -2
- package/build/api-client.cjs +2380 -2508
- package/build/api-client.cjs.map +1 -1
- package/build/api-client.modern.js +2220 -2349
- package/build/api-client.modern.js.map +1 -1
- package/build/client.d.ts +2 -2
- package/build/constants-internal.d.ts +5 -5
- package/build/constants.d.ts +6 -6
- package/build/deck/get-data-filter-extension-props.d.ts +18 -0
- package/build/deck/index.d.ts +1 -0
- package/build/filters/Filter.d.ts +15 -3
- package/build/filters/FilterTypes.d.ts +1 -1
- package/build/filters/geosjonFeatures.d.ts +2 -2
- package/build/filters/tileFeatures.d.ts +10 -9
- package/build/filters/tileFeaturesRaster.d.ts +16 -0
- package/build/filters.d.ts +2 -2
- package/build/geo.d.ts +1 -1
- package/build/index.d.ts +2 -0
- package/build/models/common.d.ts +4 -3
- package/build/models/model.d.ts +2 -2
- package/build/operations/aggregation.d.ts +5 -5
- package/build/operations/applySorting.d.ts +3 -3
- package/build/operations/groupBy.d.ts +4 -4
- package/build/operations/groupByDate.d.ts +1 -1
- package/build/operations/histogram.d.ts +3 -3
- package/build/operations/scatterPlot.d.ts +3 -3
- package/build/sources/base-source.d.ts +2 -2
- package/build/sources/boundary-query-source.d.ts +1 -1
- package/build/sources/boundary-table-source.d.ts +1 -1
- package/build/sources/h3-query-source.d.ts +2 -2
- package/build/sources/h3-table-source.d.ts +2 -2
- package/build/sources/h3-tileset-source.d.ts +2 -2
- package/build/sources/index.d.ts +26 -26
- package/build/sources/quadbin-query-source.d.ts +2 -2
- package/build/sources/quadbin-table-source.d.ts +2 -2
- package/build/sources/quadbin-tileset-source.d.ts +2 -2
- package/build/sources/raster-source.d.ts +3 -2
- package/build/sources/types.d.ts +4 -4
- package/build/sources/vector-query-source.d.ts +1 -1
- package/build/sources/vector-table-source.d.ts +1 -1
- package/build/sources/vector-tileset-source.d.ts +2 -2
- package/build/spatial-index.d.ts +10 -4
- package/build/types-internal.d.ts +5 -5
- package/build/types.d.ts +23 -15
- package/build/utils/makeIntervalComplete.d.ts +1 -1
- package/build/utils.d.ts +3 -3
- package/build/widget-sources/index.d.ts +1 -0
- package/build/widget-sources/types.d.ts +4 -2
- package/build/widget-sources/widget-query-source.d.ts +2 -1
- package/build/widget-sources/widget-raster-source.d.ts +11 -0
- package/build/widget-sources/widget-remote-source.d.ts +3 -0
- package/build/widget-sources/widget-source.d.ts +3 -3
- package/build/widget-sources/widget-table-source.d.ts +2 -1
- package/build/widget-sources/widget-tileset-source.d.ts +21 -22
- package/package.json +44 -32
- package/src/api/carto-api-error.ts +1 -1
- package/src/api/query.ts +5 -5
- package/src/api/request-with-parameters.ts +6 -6
- package/src/client.ts +3 -3
- package/src/constants-internal.ts +5 -5
- package/src/constants.ts +6 -6
- package/src/deck/get-data-filter-extension-props.ts +146 -0
- package/src/deck/index.ts +1 -0
- package/src/filters/Filter.ts +18 -8
- package/src/filters/FilterTypes.ts +2 -2
- package/src/filters/geosjonFeatures.ts +2 -2
- package/src/filters/tileFeatures.ts +33 -23
- package/src/filters/tileFeaturesRaster.ts +111 -0
- package/src/filters.ts +4 -4
- package/src/geo.ts +12 -14
- package/src/index.ts +3 -0
- package/src/models/common.ts +9 -7
- package/src/models/model.ts +3 -4
- package/src/operations/aggregation.ts +5 -5
- package/src/operations/applySorting.ts +4 -4
- package/src/operations/groupBy.ts +4 -4
- package/src/operations/groupByDate.ts +1 -1
- package/src/operations/histogram.ts +4 -4
- package/src/operations/scatterPlot.ts +4 -4
- package/src/sources/base-source.ts +8 -8
- package/src/sources/boundary-query-source.ts +2 -2
- package/src/sources/boundary-table-source.ts +2 -2
- package/src/sources/h3-query-source.ts +7 -5
- package/src/sources/h3-table-source.ts +7 -5
- package/src/sources/h3-tileset-source.ts +4 -4
- package/src/sources/index.ts +26 -26
- package/src/sources/quadbin-query-source.ts +7 -5
- package/src/sources/quadbin-table-source.ts +7 -5
- package/src/sources/quadbin-tileset-source.ts +4 -4
- package/src/sources/raster-source.ts +20 -7
- package/src/sources/types.ts +4 -4
- package/src/sources/vector-query-source.ts +2 -3
- package/src/sources/vector-table-source.ts +2 -3
- package/src/sources/vector-tileset-source.ts +5 -5
- package/src/spatial-index.ts +12 -10
- package/src/types-internal.ts +5 -5
- package/src/types.ts +21 -15
- package/src/utils/makeIntervalComplete.ts +1 -1
- package/src/utils.ts +3 -3
- package/src/widget-sources/index.ts +1 -0
- package/src/widget-sources/types.ts +5 -3
- package/src/widget-sources/widget-query-source.ts +6 -2
- package/src/widget-sources/widget-raster-source.ts +14 -0
- package/src/widget-sources/widget-remote-source.ts +31 -16
- package/src/widget-sources/widget-source.ts +13 -4
- package/src/widget-sources/widget-table-source.ts +6 -2
- package/src/widget-sources/widget-tileset-source.ts +133 -85
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import {Feature} from 'geojson';
|
|
2
|
+
import {FilterLogicalOperator, Filters} from '../types.js';
|
|
3
|
+
import {FilterType} from '../constants.js';
|
|
4
|
+
import {_buildFeatureFilter} from '../filters/index.js';
|
|
5
|
+
import {FeatureData} from '../types-internal.js';
|
|
6
|
+
|
|
7
|
+
type TimeFilter = Filters['string'][FilterType.TIME] & {
|
|
8
|
+
params?: {offsetBy?: number};
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/** @experimental Prefer type definition from deck.gl. */
|
|
12
|
+
export type _DataFilterExtensionProps = {
|
|
13
|
+
filterRange: number[][];
|
|
14
|
+
updateTriggers: Record<string, string>;
|
|
15
|
+
getFilterValue: (feature: Feature | FeatureData) => number[];
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Creates props for DataFilterExtension, from `@deck.gl/extensions`, given
|
|
20
|
+
* a set of filters.
|
|
21
|
+
*
|
|
22
|
+
* @privateRemarks DataFilterExtension accepts up to 4 values to filter. This
|
|
23
|
+
* implementation uses the 1st for all filters except the time filter, and the
|
|
24
|
+
* 2nd for the time filter.
|
|
25
|
+
*/
|
|
26
|
+
export function getDataFilterExtensionProps(
|
|
27
|
+
filters: Filters,
|
|
28
|
+
filtersLogicalOperator?: FilterLogicalOperator,
|
|
29
|
+
filterSize?: 0 | 1 | 2 | 3 | 4
|
|
30
|
+
): _DataFilterExtensionProps {
|
|
31
|
+
filterSize ??= 4;
|
|
32
|
+
const {filtersWithoutTimeType, timeColumn, timeFilter} =
|
|
33
|
+
getFiltersByType(filters);
|
|
34
|
+
return {
|
|
35
|
+
filterRange: getFilterRange(timeFilter, filterSize),
|
|
36
|
+
updateTriggers: getUpdateTriggers(
|
|
37
|
+
filtersWithoutTimeType,
|
|
38
|
+
timeColumn,
|
|
39
|
+
timeFilter
|
|
40
|
+
),
|
|
41
|
+
getFilterValue: getFilterValue(
|
|
42
|
+
filtersWithoutTimeType,
|
|
43
|
+
timeColumn,
|
|
44
|
+
timeFilter,
|
|
45
|
+
filterSize,
|
|
46
|
+
filtersLogicalOperator
|
|
47
|
+
),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** @internal */
|
|
52
|
+
function getFiltersByType(filters: Filters) {
|
|
53
|
+
const filtersWithoutTimeType: Filters = {};
|
|
54
|
+
|
|
55
|
+
let timeColumn: string | null = null;
|
|
56
|
+
let timeFilter: TimeFilter | null = null;
|
|
57
|
+
|
|
58
|
+
for (const [column, columnData] of Object.entries(filters)) {
|
|
59
|
+
for (const [type, typeData] of Object.entries(columnData) as [
|
|
60
|
+
FilterType,
|
|
61
|
+
unknown,
|
|
62
|
+
][]) {
|
|
63
|
+
if (type === FilterType.TIME) {
|
|
64
|
+
timeColumn = column;
|
|
65
|
+
timeFilter = typeData as TimeFilter;
|
|
66
|
+
} else {
|
|
67
|
+
filtersWithoutTimeType[column] = {[type]: typeData};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
filtersWithoutTimeType,
|
|
74
|
+
timeColumn,
|
|
75
|
+
timeFilter,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** @internal */
|
|
80
|
+
function getFilterRange(
|
|
81
|
+
timeFilter: TimeFilter | null,
|
|
82
|
+
filterSize: number
|
|
83
|
+
): number[][] {
|
|
84
|
+
const result = Array(filterSize).fill([0, 0]);
|
|
85
|
+
// According to getFilterValue all filters are resolved as 0 or 1 in the first position of the array
|
|
86
|
+
// except the time filter value that is resolved with the real value of the feature in the second position of the array
|
|
87
|
+
result[0] = [1, 1];
|
|
88
|
+
if (timeFilter) {
|
|
89
|
+
const offsetBy = timeFilter.params?.offsetBy || 0;
|
|
90
|
+
result[1] = timeFilter.values[0].map((v) => v - offsetBy);
|
|
91
|
+
}
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** @internal */
|
|
96
|
+
function getUpdateTriggers(
|
|
97
|
+
filtersWithoutTimeType: Filters,
|
|
98
|
+
timeColumn: string | null,
|
|
99
|
+
timeFilter: TimeFilter | null
|
|
100
|
+
) {
|
|
101
|
+
const result: Record<string, object> = {...filtersWithoutTimeType};
|
|
102
|
+
|
|
103
|
+
// We don't want to change the layer UpdateTriggers every time that the time filter changes
|
|
104
|
+
// because this filter is changed by the time series widget during its animation
|
|
105
|
+
// so we remove the time filter value from the `updateTriggers`
|
|
106
|
+
if (timeColumn && timeFilter) {
|
|
107
|
+
result[timeColumn] = {
|
|
108
|
+
...result[timeColumn],
|
|
109
|
+
offsetBy: timeFilter.params?.offsetBy,
|
|
110
|
+
[FilterType.TIME]: {}, // Allows working with other filters, without an impact on performance.
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
getFilterValue: JSON.stringify(result),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** @internal */
|
|
119
|
+
function getFilterValue(
|
|
120
|
+
filtersWithoutTimeType: Filters,
|
|
121
|
+
timeColumn: string | null,
|
|
122
|
+
timeFilter: TimeFilter | null,
|
|
123
|
+
filterSize: number,
|
|
124
|
+
filtersLogicalOperator?: FilterLogicalOperator
|
|
125
|
+
) {
|
|
126
|
+
const result = Array(filterSize).fill(0);
|
|
127
|
+
const featureFilter = _buildFeatureFilter({
|
|
128
|
+
filters: filtersWithoutTimeType,
|
|
129
|
+
type: 'number',
|
|
130
|
+
filtersLogicalOperator,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// We evaluate all filters except the time filter using _buildFeatureFilter function.
|
|
134
|
+
// For the time filter, we return the value of the feature and we will change the getFilterRange result
|
|
135
|
+
// every time this filter changes
|
|
136
|
+
return (feature: Feature | FeatureData) => {
|
|
137
|
+
result[0] = featureFilter(feature);
|
|
138
|
+
|
|
139
|
+
if (timeColumn && timeFilter) {
|
|
140
|
+
const offsetBy = timeFilter.params?.offsetBy || 0;
|
|
141
|
+
const f = (feature.properties || feature) as Record<string, unknown>;
|
|
142
|
+
result[1] = (f[timeColumn] as number) - offsetBy;
|
|
143
|
+
}
|
|
144
|
+
return result;
|
|
145
|
+
};
|
|
146
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './get-data-filter-extension-props.js';
|
package/src/filters/Filter.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {filterFunctions} from './FilterTypes';
|
|
2
|
-
import {Filter, FilterLogicalOperator, Filters} from '../types';
|
|
1
|
+
import {filterFunctions} from './FilterTypes.js';
|
|
2
|
+
import {Filter, FilterLogicalOperator, Filters} from '../types.js';
|
|
3
3
|
import {Feature} from 'geojson';
|
|
4
|
-
import {FilterType} from '../constants';
|
|
5
|
-
import {FeatureData} from '../types-internal';
|
|
4
|
+
import {FilterType} from '../constants.js';
|
|
5
|
+
import {FeatureData} from '../types-internal.js';
|
|
6
6
|
import {BinaryFeature} from '@loaders.gl/schema';
|
|
7
7
|
|
|
8
8
|
const LOGICAL_OPERATOR_METHODS: Record<
|
|
@@ -44,7 +44,11 @@ function passesFilter(
|
|
|
44
44
|
});
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
/**
|
|
48
|
+
* @internal
|
|
49
|
+
* @privateRemarks Exported for use in @deck.gl/carto's getDataFilterExtensionProps.
|
|
50
|
+
*/
|
|
51
|
+
export function _buildFeatureFilter({
|
|
48
52
|
filters = {},
|
|
49
53
|
type = 'boolean',
|
|
50
54
|
filtersLogicalOperator = 'and',
|
|
@@ -74,18 +78,24 @@ export function buildFeatureFilter({
|
|
|
74
78
|
};
|
|
75
79
|
}
|
|
76
80
|
|
|
77
|
-
|
|
81
|
+
/**
|
|
82
|
+
* Apply certain filters to a collection of features.
|
|
83
|
+
* @internal
|
|
84
|
+
*/
|
|
78
85
|
export function applyFilters(
|
|
79
86
|
features: FeatureData[],
|
|
80
87
|
filters: Filters,
|
|
81
88
|
filtersLogicalOperator: FilterLogicalOperator
|
|
82
89
|
) {
|
|
83
90
|
return Object.keys(filters).length
|
|
84
|
-
? features.filter(
|
|
91
|
+
? features.filter(_buildFeatureFilter({filters, filtersLogicalOperator}))
|
|
85
92
|
: features;
|
|
86
93
|
}
|
|
87
94
|
|
|
88
|
-
|
|
95
|
+
/**
|
|
96
|
+
* Binary.
|
|
97
|
+
* @internal
|
|
98
|
+
*/
|
|
89
99
|
export function buildBinaryFeatureFilter({filters = {}}: {filters: Filters}) {
|
|
90
100
|
const columns = Object.keys(filters);
|
|
91
101
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {FilterType} from '../constants';
|
|
2
|
-
import {FilterInterval, StringSearchOptions} from '../types';
|
|
1
|
+
import {FilterType} from '../constants.js';
|
|
2
|
+
import {FilterInterval, StringSearchOptions} from '../types.js';
|
|
3
3
|
import {makeIntervalComplete} from '../utils/makeIntervalComplete.js';
|
|
4
4
|
|
|
5
5
|
export type FilterFunction = (
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import intersects from '@turf/boolean-intersects';
|
|
2
2
|
import {FeatureCollection} from 'geojson';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import {FeatureData} from '../types-internal.js';
|
|
4
|
+
import {SpatialFilter} from '../types.js';
|
|
5
5
|
|
|
6
6
|
export function geojsonFeatures({
|
|
7
7
|
geojson,
|
|
@@ -1,28 +1,31 @@
|
|
|
1
|
-
import {SpatialFilter, SpatialIndexTile, Tile} from '../types';
|
|
2
|
-
import {tileFeaturesGeometries} from './tileFeaturesGeometries';
|
|
3
|
-
import {tileFeaturesSpatialIndex} from './tileFeaturesSpatialIndex';
|
|
4
|
-
import {
|
|
5
|
-
import {DEFAULT_GEO_COLUMN} from '../constants-internal';
|
|
6
|
-
import {FeatureData} from '../types-internal';
|
|
7
|
-
import {SpatialDataType} from '../sources/types';
|
|
1
|
+
import {RasterTile, SpatialFilter, SpatialIndexTile, Tile} from '../types.js';
|
|
2
|
+
import {tileFeaturesGeometries} from './tileFeaturesGeometries.js';
|
|
3
|
+
import {tileFeaturesSpatialIndex} from './tileFeaturesSpatialIndex.js';
|
|
4
|
+
import {TileFormat} from '../constants.js';
|
|
5
|
+
import {DEFAULT_GEO_COLUMN} from '../constants-internal.js';
|
|
6
|
+
import {FeatureData} from '../types-internal.js';
|
|
7
|
+
import {RasterMetadata, SpatialDataType} from '../sources/types.js';
|
|
8
|
+
import {isRasterTile, tileFeaturesRaster} from './tileFeaturesRaster.js';
|
|
9
|
+
import {assert} from '../utils.js';
|
|
8
10
|
|
|
9
|
-
/** @
|
|
11
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
10
12
|
export type TileFeatures = {
|
|
11
13
|
tiles: Tile[];
|
|
12
14
|
tileFormat: TileFormat;
|
|
13
15
|
spatialDataType: SpatialDataType;
|
|
14
16
|
spatialDataColumn?: string;
|
|
15
|
-
spatialFilter
|
|
17
|
+
spatialFilter: SpatialFilter;
|
|
16
18
|
uniqueIdProperty?: string;
|
|
19
|
+
rasterMetadata?: RasterMetadata;
|
|
17
20
|
options?: TileFeatureExtractOptions;
|
|
18
21
|
};
|
|
19
22
|
|
|
20
|
-
/** @
|
|
23
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
21
24
|
export type TileFeatureExtractOptions = {
|
|
22
25
|
storeGeometry?: boolean;
|
|
23
26
|
};
|
|
24
27
|
|
|
25
|
-
/** @
|
|
28
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
26
29
|
export function tileFeatures({
|
|
27
30
|
tiles,
|
|
28
31
|
spatialFilter,
|
|
@@ -30,27 +33,34 @@ export function tileFeatures({
|
|
|
30
33
|
tileFormat,
|
|
31
34
|
spatialDataColumn = DEFAULT_GEO_COLUMN,
|
|
32
35
|
spatialDataType,
|
|
36
|
+
rasterMetadata,
|
|
33
37
|
options = {},
|
|
34
38
|
}: TileFeatures): FeatureData[] {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
if (spatialDataType === 'geo') {
|
|
40
|
+
return tileFeaturesGeometries({
|
|
41
|
+
tiles,
|
|
42
|
+
tileFormat,
|
|
43
|
+
spatialFilter,
|
|
44
|
+
uniqueIdProperty,
|
|
45
|
+
options,
|
|
46
|
+
});
|
|
39
47
|
}
|
|
40
48
|
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
|
|
49
|
+
if (tiles.some(isRasterTile)) {
|
|
50
|
+
assert(rasterMetadata, 'Missing raster metadata');
|
|
51
|
+
return tileFeaturesRaster({
|
|
52
|
+
tiles: tiles as RasterTile[],
|
|
44
53
|
spatialFilter,
|
|
45
54
|
spatialDataColumn,
|
|
46
55
|
spatialDataType,
|
|
56
|
+
rasterMetadata,
|
|
47
57
|
});
|
|
48
58
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
59
|
+
|
|
60
|
+
return tileFeaturesSpatialIndex({
|
|
61
|
+
tiles: tiles as SpatialIndexTile[],
|
|
52
62
|
spatialFilter,
|
|
53
|
-
|
|
54
|
-
|
|
63
|
+
spatialDataColumn,
|
|
64
|
+
spatialDataType,
|
|
55
65
|
});
|
|
56
66
|
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cellToChildren as _cellToChildren,
|
|
3
|
+
cellToTile,
|
|
4
|
+
geometryToCells,
|
|
5
|
+
getResolution,
|
|
6
|
+
} from 'quadbin';
|
|
7
|
+
import {RasterTile, SpatialFilter, Tile} from '../types.js';
|
|
8
|
+
import {FeatureData} from '../types-internal.js';
|
|
9
|
+
import {
|
|
10
|
+
RasterMetadata,
|
|
11
|
+
RasterMetadataBand,
|
|
12
|
+
SpatialDataType,
|
|
13
|
+
} from '../sources/types.js';
|
|
14
|
+
|
|
15
|
+
export type TileFeaturesRasterOptions = {
|
|
16
|
+
tiles: RasterTile[];
|
|
17
|
+
spatialFilter: SpatialFilter;
|
|
18
|
+
spatialDataColumn: string;
|
|
19
|
+
spatialDataType: SpatialDataType;
|
|
20
|
+
rasterMetadata: RasterMetadata;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export function tileFeaturesRaster({
|
|
24
|
+
tiles,
|
|
25
|
+
...options
|
|
26
|
+
}: TileFeaturesRasterOptions): FeatureData[] {
|
|
27
|
+
// Cache band metadata for faster lookup while iterating over pixels.
|
|
28
|
+
const bandMetadataByName: Record<string, RasterMetadataBand> = {};
|
|
29
|
+
for (const band of options.rasterMetadata.bands) {
|
|
30
|
+
bandMetadataByName[band.name] = band;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Omit empty and invisible tiles for simpler processing and types.
|
|
34
|
+
tiles = tiles.filter(isRasterTileVisible);
|
|
35
|
+
if (tiles.length === 0) return [];
|
|
36
|
+
|
|
37
|
+
// Raster tiles, and all pixels, are quadbin cells. Resolution of a pixel is
|
|
38
|
+
// the resolution of the tile, plus the number of subdivisions. Block size
|
|
39
|
+
// must be square, N x N, where N is a power of two.
|
|
40
|
+
const tileResolution = getResolution(tiles[0].index.q);
|
|
41
|
+
const tileBlockSize = tiles[0].data!.blockSize;
|
|
42
|
+
const cellResolution = tileResolution + BigInt(Math.log2(tileBlockSize));
|
|
43
|
+
|
|
44
|
+
// Compute covering cells for the spatial filter, at same resolution as the
|
|
45
|
+
// raster pixels, to be used as a mask.
|
|
46
|
+
const spatialFilterCells = new Set(
|
|
47
|
+
geometryToCells(options.spatialFilter, cellResolution)
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const data = new Map<bigint, FeatureData>();
|
|
51
|
+
|
|
52
|
+
for (const tile of tiles as Required<RasterTile>[]) {
|
|
53
|
+
const parent = tile.index.q;
|
|
54
|
+
|
|
55
|
+
const children = cellToChildrenSorted(parent, cellResolution);
|
|
56
|
+
|
|
57
|
+
// For each pixel/cell within the spatial filter, create a FeatureData.
|
|
58
|
+
// Order is row-major, starting from NW and ending at SE.
|
|
59
|
+
for (let i = 0; i < children.length; i++) {
|
|
60
|
+
if (!spatialFilterCells.has(children[i])) continue;
|
|
61
|
+
|
|
62
|
+
const cellData: FeatureData = {};
|
|
63
|
+
let cellDataExists = false;
|
|
64
|
+
|
|
65
|
+
for (const band in tile.data.cells.numericProps) {
|
|
66
|
+
const value = tile.data.cells.numericProps[band].value[i];
|
|
67
|
+
// TODO(cleanup): nodata should be a number, not a string.
|
|
68
|
+
if (Number(bandMetadataByName[band].nodata) !== value) {
|
|
69
|
+
cellData[band] = tile.data.cells.numericProps[band].value[i];
|
|
70
|
+
cellDataExists = true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (cellDataExists) {
|
|
75
|
+
data.set(children[i], cellData);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return Array.from(data.values());
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Detects whether a given {@link Tile} is a {@link RasterTile}.
|
|
85
|
+
* @privateRemarks Method of detection is arbitrary, and may be changed.
|
|
86
|
+
*/
|
|
87
|
+
export function isRasterTile(tile: Tile): tile is RasterTile {
|
|
88
|
+
return !!(tile.data as Record<string, unknown>)?.cells;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function isRasterTileVisible(tile: RasterTile): tile is Required<RasterTile> {
|
|
92
|
+
return !!(tile.isVisible && tile.data?.cells?.numericProps);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* For the raster format, children are sorted in row-major order, starting from
|
|
97
|
+
* NW and ending at SE. Order returned by quadbin's cellToChildren() is not
|
|
98
|
+
* defined (and not related to the raster format), so sort explicitly here.
|
|
99
|
+
*/
|
|
100
|
+
function cellToChildrenSorted(parent: bigint, resolution: bigint): bigint[] {
|
|
101
|
+
return _cellToChildren(parent, resolution).sort(
|
|
102
|
+
(cellA: bigint, cellB: bigint) => {
|
|
103
|
+
const tileA = cellToTile(cellA);
|
|
104
|
+
const tileB = cellToTile(cellB);
|
|
105
|
+
if (tileA.y !== tileB.y) {
|
|
106
|
+
return tileA.y > tileB.y ? 1 : -1;
|
|
107
|
+
}
|
|
108
|
+
return tileA.x > tileB.x ? 1 : -1;
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
}
|
package/src/filters.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {FilterType} from './constants';
|
|
2
|
-
import {Filter} from './types';
|
|
3
|
-
import {isEmptyObject} from './utils';
|
|
1
|
+
import {FilterType} from './constants.js';
|
|
2
|
+
import {Filter} from './types.js';
|
|
3
|
+
import {isEmptyObject} from './utils.js';
|
|
4
4
|
|
|
5
5
|
type FilterTypeOptions<T extends FilterType> = {
|
|
6
6
|
type: T;
|
|
@@ -121,7 +121,7 @@ export function getFilter<T extends FilterType>(
|
|
|
121
121
|
return null;
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
if (!owner || owner === filter[type
|
|
124
|
+
if (!owner || owner === filter[type]?.owner) {
|
|
125
125
|
return filter[type] || null;
|
|
126
126
|
}
|
|
127
127
|
|
package/src/geo.ts
CHANGED
|
@@ -4,7 +4,7 @@ import union from '@turf/union';
|
|
|
4
4
|
import {getType} from '@turf/invariant';
|
|
5
5
|
import {polygon, multiPolygon, feature, featureCollection} from '@turf/helpers';
|
|
6
6
|
import type {BBox, Geometry, MultiPolygon, Polygon, Position} from 'geojson';
|
|
7
|
-
import {SpatialFilter} from './types';
|
|
7
|
+
import {SpatialFilter} from './types.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Returns a {@link SpatialFilter} for a given viewport, typically obtained
|
|
@@ -40,7 +40,7 @@ export function createPolygonSpatialFilter(
|
|
|
40
40
|
* Check if a viewport is large enough to represent a global coverage.
|
|
41
41
|
* In this case the spatial filter parameter for widget calculation is removed.
|
|
42
42
|
*
|
|
43
|
-
* @
|
|
43
|
+
* @privateRemarks Source: @carto/react-core
|
|
44
44
|
*/
|
|
45
45
|
function _isGlobalViewport(viewport: BBox) {
|
|
46
46
|
const [minx, miny, maxx, maxy] = viewport;
|
|
@@ -54,7 +54,7 @@ function _isGlobalViewport(viewport: BBox) {
|
|
|
54
54
|
*
|
|
55
55
|
* It results in a Polygon or MultiPolygon strictly inside the validity range.
|
|
56
56
|
*
|
|
57
|
-
* @
|
|
57
|
+
* @privateRemarks Source: @carto/react-core
|
|
58
58
|
*/
|
|
59
59
|
function _normalizeGeometry(
|
|
60
60
|
geometry: Polygon | MultiPolygon
|
|
@@ -100,19 +100,19 @@ function _normalizeGeometry(
|
|
|
100
100
|
return result;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
/** @
|
|
103
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
104
104
|
function _cleanPolygonCoords(cc: Position[][]) {
|
|
105
105
|
const coords = cc.filter((c) => c.length > 0);
|
|
106
106
|
return coords.length > 0 ? coords : null;
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
/** @
|
|
109
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
110
110
|
function _cleanMultiPolygonCoords(ccc: Position[][][]) {
|
|
111
111
|
const coords = ccc.map(_cleanPolygonCoords).filter((cc) => cc);
|
|
112
112
|
return coords.length > 0 ? coords : null;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
/** @
|
|
115
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
116
116
|
function _clean(
|
|
117
117
|
geometry: Polygon | MultiPolygon | null
|
|
118
118
|
): Polygon | MultiPolygon | null {
|
|
@@ -121,36 +121,34 @@ function _clean(
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
if (_isPolygon(geometry)) {
|
|
124
|
-
const coords = _cleanPolygonCoords(
|
|
124
|
+
const coords = _cleanPolygonCoords(geometry.coordinates);
|
|
125
125
|
return coords ? polygon(coords).geometry : null;
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
if (_isMultiPolygon(geometry)) {
|
|
129
|
-
const coords = _cleanMultiPolygonCoords(
|
|
130
|
-
(geometry as MultiPolygon).coordinates
|
|
131
|
-
);
|
|
129
|
+
const coords = _cleanMultiPolygonCoords(geometry.coordinates);
|
|
132
130
|
return coords ? multiPolygon(coords as Position[][][]).geometry : null;
|
|
133
131
|
}
|
|
134
132
|
|
|
135
133
|
return null;
|
|
136
134
|
}
|
|
137
135
|
|
|
138
|
-
/** @
|
|
136
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
139
137
|
function _txContourCoords(cc: Position[], distance: number) {
|
|
140
138
|
return cc.map((c) => [c[0] + distance, c[1]]);
|
|
141
139
|
}
|
|
142
140
|
|
|
143
|
-
/** @
|
|
141
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
144
142
|
function _txPolygonCoords(ccc: Position[][], distance: number) {
|
|
145
143
|
return ccc.map((cc) => _txContourCoords(cc, distance));
|
|
146
144
|
}
|
|
147
145
|
|
|
148
|
-
/** @
|
|
146
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
149
147
|
function _txMultiPolygonCoords(cccc: Position[][][], distance: number) {
|
|
150
148
|
return cccc.map((ccc) => _txPolygonCoords(ccc, distance));
|
|
151
149
|
}
|
|
152
150
|
|
|
153
|
-
/** @
|
|
151
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
154
152
|
function _tx(geometry: Polygon | MultiPolygon, distance: number) {
|
|
155
153
|
if (geometry && getType(geometry) === 'Polygon') {
|
|
156
154
|
const coords = _txPolygonCoords(
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * from './client.js';
|
|
2
2
|
export * from './constants.js';
|
|
3
|
+
export * from './deck/index.js';
|
|
3
4
|
export * from './filters.js';
|
|
4
5
|
export * from './geo.js';
|
|
5
6
|
export * from './sources/index.js';
|
|
@@ -17,6 +18,8 @@ export {
|
|
|
17
18
|
requestWithParameters,
|
|
18
19
|
} from './api/index.js';
|
|
19
20
|
|
|
21
|
+
export {_getHexagonResolution} from './spatial-index.js';
|
|
22
|
+
|
|
20
23
|
// For unit testing only.
|
|
21
24
|
export * from './filters/index.js';
|
|
22
25
|
export * from './operations/index.js';
|
package/src/models/common.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import {InvalidColumnError} from '../utils.js';
|
|
2
2
|
|
|
3
|
-
/** @
|
|
3
|
+
/** @privateRemarks Source: @carto/react-api */
|
|
4
4
|
export interface ModelRequestOptions {
|
|
5
5
|
method: 'GET' | 'POST';
|
|
6
|
+
headers?: Record<string, string>;
|
|
6
7
|
abortController?: AbortController;
|
|
7
8
|
otherOptions?: Record<string, unknown>;
|
|
8
9
|
body?: string;
|
|
@@ -16,7 +17,7 @@ interface ModelErrorResponse {
|
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
19
|
* Return more descriptive error from API
|
|
19
|
-
* @
|
|
20
|
+
* @privateRemarks Source: @carto/react-api
|
|
20
21
|
*/
|
|
21
22
|
export function dealWithApiError({
|
|
22
23
|
response,
|
|
@@ -42,15 +43,15 @@ export function dealWithApiError({
|
|
|
42
43
|
case 403:
|
|
43
44
|
throw new Error('Forbidden access to the requested data');
|
|
44
45
|
default:
|
|
45
|
-
|
|
46
|
+
throw new Error(
|
|
46
47
|
data && data.error && typeof data.error === 'string'
|
|
47
48
|
? data.error
|
|
48
|
-
: JSON.stringify(data?.hint || data.error?.[0])
|
|
49
|
-
|
|
49
|
+
: JSON.stringify(data?.hint || data.error?.[0])
|
|
50
|
+
);
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
53
|
|
|
53
|
-
/** @
|
|
54
|
+
/** @privateRemarks Source: @carto/react-api */
|
|
54
55
|
export async function makeCall({
|
|
55
56
|
url,
|
|
56
57
|
accessToken,
|
|
@@ -68,6 +69,7 @@ export async function makeCall({
|
|
|
68
69
|
headers: {
|
|
69
70
|
Authorization: `Bearer ${accessToken}`,
|
|
70
71
|
...(isPost && {'Content-Type': 'application/json'}),
|
|
72
|
+
...opts.headers,
|
|
71
73
|
},
|
|
72
74
|
...(isPost && {
|
|
73
75
|
method: opts?.method,
|
|
@@ -80,7 +82,7 @@ export async function makeCall({
|
|
|
80
82
|
} catch (error) {
|
|
81
83
|
if ((error as Error).name === 'AbortError') throw error;
|
|
82
84
|
|
|
83
|
-
throw new Error(`Failed request: ${error}`);
|
|
85
|
+
throw new Error(`Failed request: ${error as Error}`);
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
if (!response.ok) {
|
package/src/models/model.ts
CHANGED
|
@@ -6,13 +6,12 @@ import {
|
|
|
6
6
|
QueryParameters,
|
|
7
7
|
SpatialFilter,
|
|
8
8
|
} from '../types.js';
|
|
9
|
-
import {$TODO} from '../types-internal.js';
|
|
10
9
|
import {assert, isPureObject} from '../utils.js';
|
|
11
10
|
import {ModelRequestOptions, makeCall} from './common.js';
|
|
12
11
|
import {ApiVersion} from '../constants.js';
|
|
13
12
|
import {SpatialDataType, SpatialFilterPolyfillMode} from '../sources/types.js';
|
|
14
13
|
|
|
15
|
-
/** @
|
|
14
|
+
/** @privateRemarks Source: @carto/react-api */
|
|
16
15
|
const AVAILABLE_MODELS = [
|
|
17
16
|
'category',
|
|
18
17
|
'histogram',
|
|
@@ -51,7 +50,7 @@ const REQUEST_GET_MAX_URL_LENGTH = 2048;
|
|
|
51
50
|
|
|
52
51
|
/**
|
|
53
52
|
* Execute a SQL model request.
|
|
54
|
-
* @
|
|
53
|
+
* @privateRemarks Source: @carto/react-api
|
|
55
54
|
*/
|
|
56
55
|
export function executeModel(props: {
|
|
57
56
|
model: Model;
|
|
@@ -152,7 +151,7 @@ function objectToURLSearchParams(object: Record<string, unknown>) {
|
|
|
152
151
|
} else if (object[key] === null) {
|
|
153
152
|
params.append(key, 'null');
|
|
154
153
|
} else if (object[key] !== undefined) {
|
|
155
|
-
params.append(key, String(object[key]));
|
|
154
|
+
params.append(key, String(object[key] as unknown));
|
|
156
155
|
}
|
|
157
156
|
}
|
|
158
157
|
return params;
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import {AggregationType} from '../types';
|
|
2
|
-
import {FeatureData} from '../types-internal';
|
|
1
|
+
import {AggregationType} from '../types.js';
|
|
2
|
+
import {FeatureData} from '../types-internal.js';
|
|
3
3
|
|
|
4
|
-
/** @
|
|
4
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
5
5
|
export type AggregationFunction = (
|
|
6
6
|
values: unknown[] | FeatureData[],
|
|
7
7
|
keys?: string[] | string,
|
|
8
8
|
joinOperation?: AggregationType
|
|
9
9
|
) => number;
|
|
10
10
|
|
|
11
|
-
/** @
|
|
11
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
12
12
|
export const aggregationFunctions: Record<
|
|
13
13
|
Exclude<AggregationType, 'custom'>,
|
|
14
14
|
AggregationFunction
|
|
@@ -20,7 +20,7 @@ export const aggregationFunctions: Record<
|
|
|
20
20
|
avg: (...args) => applyAggregationFunction(avg, ...args),
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
-
/** @
|
|
23
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
24
24
|
export function aggregate(
|
|
25
25
|
feature: FeatureData,
|
|
26
26
|
keys?: string[],
|