@carto/api-client 0.5.0-alpha.3 → 0.5.0-alpha.5
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-client.cjs +3332 -3100
- package/build/api-client.d.cts +1373 -0
- package/build/api-client.d.ts +1373 -0
- package/build/api-client.js +1712 -0
- package/build/chunk-V3E7BKVR.js +2063 -0
- package/build/worker.d.ts +2 -0
- package/build/worker.js +25 -0
- package/package.json +51 -45
- 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 -11
- 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 +19 -41
- package/src/filters.ts +4 -4
- package/src/geo.ts +12 -14
- package/src/global.d.ts +3 -8
- package/src/index.ts +1 -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 +12 -5
- 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 +12 -5
- package/src/sources/raster-source.ts +7 -16
- package/src/sources/types.ts +10 -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 +13 -6
- package/src/spatial-index.ts +4 -4
- package/src/types-internal.ts +5 -5
- package/src/types.ts +15 -21
- package/src/utils/makeIntervalComplete.ts +1 -1
- package/src/utils.ts +3 -3
- package/src/widget-sources/index.ts +1 -1
- package/src/widget-sources/types.ts +5 -3
- package/src/widget-sources/widget-query-source.ts +6 -2
- package/src/widget-sources/widget-remote-source.ts +66 -18
- package/src/widget-sources/widget-source.ts +0 -28
- package/src/widget-sources/widget-table-source.ts +6 -2
- package/src/widget-sources/widget-tileset-source.ts +130 -90
- package/src/widget-sources/widget-tileset-worker-source.ts +238 -0
- package/src/workers/constants.ts +13 -0
- package/src/workers/types.ts +20 -0
- package/src/workers/utils.ts +33 -0
- package/src/workers/widget-tileset-worker.ts +36 -0
- package/build/api/carto-api-error.d.ts +0 -26
- package/build/api/endpoints.d.ts +0 -24
- package/build/api/index.d.ts +0 -5
- package/build/api/query.d.ts +0 -3
- package/build/api/request-with-parameters.d.ts +0 -10
- package/build/api-client.cjs.map +0 -1
- package/build/api-client.modern.js +0 -3304
- package/build/api-client.modern.js.map +0 -1
- package/build/client.d.ts +0 -14
- package/build/constants-internal.d.ts +0 -26
- package/build/constants.d.ts +0 -53
- package/build/filters/Filter.d.ts +0 -13
- package/build/filters/FilterTypes.d.ts +0 -3
- package/build/filters/geosjonFeatures.d.ts +0 -8
- package/build/filters/index.d.ts +0 -6
- package/build/filters/tileFeatures.d.ts +0 -21
- package/build/filters/tileFeaturesGeometries.d.ts +0 -13
- package/build/filters/tileFeaturesRaster.d.ts +0 -16
- package/build/filters/tileFeaturesSpatialIndex.d.ts +0 -10
- package/build/filters.d.ts +0 -39
- package/build/geo.d.ts +0 -19
- package/build/index.d.ts +0 -15
- package/build/models/common.d.ts +0 -27
- package/build/models/index.d.ts +0 -3
- package/build/models/model.d.ts +0 -37
- package/build/operations/aggregation.d.ts +0 -8
- package/build/operations/applySorting.d.ts +0 -20
- package/build/operations/groupBy.d.ts +0 -15
- package/build/operations/groupByDate.d.ts +0 -11
- package/build/operations/histogram.d.ts +0 -13
- package/build/operations/index.d.ts +0 -6
- package/build/operations/scatterPlot.d.ts +0 -14
- package/build/sources/base-source.d.ts +0 -4
- package/build/sources/boundary-query-source.d.ts +0 -10
- package/build/sources/boundary-table-source.d.ts +0 -8
- package/build/sources/h3-query-source.d.ts +0 -5
- package/build/sources/h3-table-source.d.ts +0 -5
- package/build/sources/h3-tileset-source.d.ts +0 -5
- package/build/sources/index.d.ts +0 -26
- package/build/sources/quadbin-query-source.d.ts +0 -5
- package/build/sources/quadbin-table-source.d.ts +0 -5
- package/build/sources/quadbin-tileset-source.d.ts +0 -5
- package/build/sources/raster-source.d.ts +0 -5
- package/build/sources/types.d.ts +0 -366
- package/build/sources/vector-query-source.d.ts +0 -5
- package/build/sources/vector-table-source.d.ts +0 -5
- package/build/sources/vector-tileset-source.d.ts +0 -5
- package/build/spatial-index.d.ts +0 -14
- package/build/types-internal.d.ts +0 -56
- package/build/types.d.ts +0 -148
- package/build/utils/dateUtils.d.ts +0 -10
- package/build/utils/getTileFormat.d.ts +0 -3
- package/build/utils/makeIntervalComplete.d.ts +0 -2
- package/build/utils/transformTileCoordsToWGS84.d.ts +0 -8
- package/build/utils/transformToTileCoords.d.ts +0 -9
- package/build/utils.d.ts +0 -32
- package/build/widget-sources/index.d.ts +0 -7
- package/build/widget-sources/types.d.ts +0 -158
- package/build/widget-sources/widget-query-source.d.ts +0 -33
- package/build/widget-sources/widget-raster-source.d.ts +0 -11
- package/build/widget-sources/widget-remote-source.d.ts +0 -18
- package/build/widget-sources/widget-source.d.ts +0 -74
- package/build/widget-sources/widget-table-source.d.ts +0 -33
- package/build/widget-sources/widget-tileset-source.d.ts +0 -77
- package/src/filters/tileFeaturesRaster.ts +0 -111
- package/src/widget-sources/widget-raster-source.ts +0 -14
|
@@ -1,9 +1,8 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/require-await */
|
|
1
2
|
import {TilesetSourceOptions} from '../sources/index.js';
|
|
2
|
-
import type {ModelSource} from '../models/index.js';
|
|
3
3
|
import {
|
|
4
4
|
CategoryRequestOptions,
|
|
5
5
|
CategoryResponse,
|
|
6
|
-
FeaturesRequestOptions,
|
|
7
6
|
FeaturesResponse,
|
|
8
7
|
FormulaRequestOptions,
|
|
9
8
|
FormulaResponse,
|
|
@@ -18,9 +17,9 @@ import {
|
|
|
18
17
|
TimeSeriesRequestOptions,
|
|
19
18
|
TimeSeriesResponse,
|
|
20
19
|
} from './types.js';
|
|
21
|
-
import {InvalidColumnError, getApplicableFilters} from '../utils.js';
|
|
20
|
+
import {InvalidColumnError, assert, getApplicableFilters} from '../utils.js';
|
|
22
21
|
import {TileFormat} from '../constants.js';
|
|
23
|
-
import {SpatialFilter, Tile} from '../types.js';
|
|
22
|
+
import {Filter, SpatialFilter, Tile} from '../types.js';
|
|
24
23
|
import {
|
|
25
24
|
TileFeatureExtractOptions,
|
|
26
25
|
applyFilters,
|
|
@@ -39,6 +38,7 @@ import {FeatureData} from '../types-internal.js';
|
|
|
39
38
|
import {FeatureCollection} from 'geojson';
|
|
40
39
|
import {SpatialDataType} from '../sources/types.js';
|
|
41
40
|
import {WidgetSource, WidgetSourceProps} from './widget-source.js';
|
|
41
|
+
import {booleanEqual} from '@turf/boolean-equal';
|
|
42
42
|
|
|
43
43
|
// TODO(cleanup): Parameter defaults in source functions and widget API calls are
|
|
44
44
|
// currently duplicated and possibly inconsistent. Consider consolidating and
|
|
@@ -75,19 +75,12 @@ export type WidgetTilesetSourceResult = {widgetSource: WidgetTilesetSource};
|
|
|
75
75
|
* const { widgetSource } = await data;
|
|
76
76
|
* ```
|
|
77
77
|
*/
|
|
78
|
-
export class WidgetTilesetSource<
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
protected override getModelSource(owner: string): ModelSource {
|
|
85
|
-
return {
|
|
86
|
-
...super._getModelSource(owner),
|
|
87
|
-
type: 'tileset',
|
|
88
|
-
data: this.props.tableName,
|
|
89
|
-
};
|
|
90
|
-
}
|
|
78
|
+
export class WidgetTilesetSource extends WidgetSource<WidgetTilesetSourceProps> {
|
|
79
|
+
private _tiles: Tile[] = [];
|
|
80
|
+
private _features: FeatureData[] = [];
|
|
81
|
+
private _tileFeatureExtractOptions: TileFeatureExtractOptions = {};
|
|
82
|
+
private _tileFeatureExtractPreviousInputs: {spatialFilter?: SpatialFilter} =
|
|
83
|
+
{};
|
|
91
84
|
|
|
92
85
|
/**
|
|
93
86
|
* Loads features as a list of tiles (typically provided by deck.gl).
|
|
@@ -96,50 +89,61 @@ export class WidgetTilesetSource<
|
|
|
96
89
|
*/
|
|
97
90
|
loadTiles(tiles: unknown[]) {
|
|
98
91
|
this._tiles = tiles as Tile[];
|
|
92
|
+
this._features.length = 0;
|
|
99
93
|
}
|
|
100
94
|
|
|
101
|
-
/**
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
95
|
+
/** Configures options used to extract features from tiles. */
|
|
96
|
+
setTileFeatureExtractOptions(options: TileFeatureExtractOptions) {
|
|
97
|
+
this._tileFeatureExtractOptions = options;
|
|
98
|
+
this._features.length = 0;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
protected _extractTileFeatures(spatialFilter: SpatialFilter) {
|
|
102
|
+
// When spatial filter has not changed, don't redo extraction. If tiles or
|
|
103
|
+
// tile extract options change, features will have been cleared already.
|
|
104
|
+
const prevInputs = this._tileFeatureExtractPreviousInputs;
|
|
105
|
+
if (
|
|
106
|
+
this._features.length &&
|
|
107
|
+
prevInputs.spatialFilter &&
|
|
108
|
+
booleanEqual(prevInputs.spatialFilter, spatialFilter)
|
|
109
|
+
) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
114
113
|
this._features = tileFeatures({
|
|
115
114
|
tiles: this._tiles,
|
|
116
|
-
|
|
115
|
+
tileFormat: this.props.tileFormat,
|
|
116
|
+
...this._tileFeatureExtractOptions,
|
|
117
|
+
|
|
117
118
|
spatialFilter,
|
|
118
|
-
|
|
119
|
-
|
|
119
|
+
spatialDataColumn: this.props.spatialDataColumn,
|
|
120
|
+
spatialDataType: this.props.spatialDataType,
|
|
120
121
|
});
|
|
122
|
+
|
|
123
|
+
prevInputs.spatialFilter = spatialFilter;
|
|
121
124
|
}
|
|
122
125
|
|
|
123
|
-
/**
|
|
126
|
+
/**
|
|
127
|
+
* Loads features as GeoJSON (used for testing).
|
|
128
|
+
* @experimental
|
|
129
|
+
* @internal Not for public use. Spatial filters in other method calls will be ignored.
|
|
130
|
+
*/
|
|
124
131
|
loadGeoJSON({
|
|
125
132
|
geojson,
|
|
126
133
|
spatialFilter,
|
|
127
|
-
uniqueIdProperty,
|
|
128
134
|
}: {
|
|
129
135
|
geojson: FeatureCollection;
|
|
130
136
|
spatialFilter: SpatialFilter;
|
|
131
|
-
uniqueIdProperty?: string;
|
|
132
137
|
}) {
|
|
133
138
|
this._features = geojsonFeatures({
|
|
134
139
|
geojson,
|
|
135
140
|
spatialFilter,
|
|
136
|
-
|
|
141
|
+
...this._tileFeatureExtractOptions,
|
|
137
142
|
});
|
|
143
|
+
this._tileFeatureExtractPreviousInputs.spatialFilter = spatialFilter;
|
|
138
144
|
}
|
|
139
145
|
|
|
140
|
-
override async getFeatures(
|
|
141
|
-
options: FeaturesRequestOptions
|
|
142
|
-
): Promise<FeaturesResponse> {
|
|
146
|
+
override async getFeatures(): Promise<FeaturesResponse> {
|
|
143
147
|
throw new Error('getFeatures not supported for tilesets');
|
|
144
148
|
}
|
|
145
149
|
|
|
@@ -147,22 +151,24 @@ export class WidgetTilesetSource<
|
|
|
147
151
|
column = '*',
|
|
148
152
|
operation = 'count',
|
|
149
153
|
joinOperation,
|
|
154
|
+
filters,
|
|
150
155
|
filterOwner,
|
|
156
|
+
spatialFilter,
|
|
151
157
|
}: FormulaRequestOptions): Promise<FormulaResponse> {
|
|
152
158
|
if (operation === 'custom') {
|
|
153
159
|
throw new Error('Custom aggregation not supported for tilesets');
|
|
154
160
|
}
|
|
155
161
|
|
|
156
|
-
if (!this._features.length) {
|
|
157
|
-
return {value: null};
|
|
158
|
-
}
|
|
159
|
-
|
|
160
162
|
// Column is required except when operation is 'count'.
|
|
161
163
|
if ((column && column !== '*') || operation !== 'count') {
|
|
162
164
|
assertColumn(this._features, column);
|
|
163
165
|
}
|
|
164
166
|
|
|
165
|
-
const filteredFeatures = this._getFilteredFeatures(
|
|
167
|
+
const filteredFeatures = this._getFilteredFeatures(
|
|
168
|
+
spatialFilter,
|
|
169
|
+
filters,
|
|
170
|
+
filterOwner
|
|
171
|
+
);
|
|
166
172
|
|
|
167
173
|
if (filteredFeatures.length === 0 && operation !== 'count') {
|
|
168
174
|
return {value: null};
|
|
@@ -170,11 +176,7 @@ export class WidgetTilesetSource<
|
|
|
170
176
|
|
|
171
177
|
const targetOperation = aggregationFunctions[operation];
|
|
172
178
|
return {
|
|
173
|
-
value: targetOperation(
|
|
174
|
-
filteredFeatures as FeatureData[],
|
|
175
|
-
column,
|
|
176
|
-
joinOperation
|
|
177
|
-
),
|
|
179
|
+
value: targetOperation(filteredFeatures, column, joinOperation),
|
|
178
180
|
};
|
|
179
181
|
}
|
|
180
182
|
|
|
@@ -183,16 +185,22 @@ export class WidgetTilesetSource<
|
|
|
183
185
|
ticks,
|
|
184
186
|
column,
|
|
185
187
|
joinOperation,
|
|
188
|
+
filters,
|
|
186
189
|
filterOwner,
|
|
190
|
+
spatialFilter,
|
|
187
191
|
}: HistogramRequestOptions): Promise<HistogramResponse> {
|
|
192
|
+
const filteredFeatures = this._getFilteredFeatures(
|
|
193
|
+
spatialFilter,
|
|
194
|
+
filters,
|
|
195
|
+
filterOwner
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
assertColumn(this._features, column);
|
|
199
|
+
|
|
188
200
|
if (!this._features.length) {
|
|
189
201
|
return [];
|
|
190
202
|
}
|
|
191
203
|
|
|
192
|
-
const filteredFeatures = this._getFilteredFeatures(filterOwner);
|
|
193
|
-
|
|
194
|
-
assertColumn(this._features, column);
|
|
195
|
-
|
|
196
204
|
return histogram({
|
|
197
205
|
data: filteredFeatures,
|
|
198
206
|
valuesColumns: normalizeColumns(column),
|
|
@@ -207,15 +215,21 @@ export class WidgetTilesetSource<
|
|
|
207
215
|
operation = 'count',
|
|
208
216
|
operationColumn,
|
|
209
217
|
joinOperation,
|
|
218
|
+
filters,
|
|
210
219
|
filterOwner,
|
|
220
|
+
spatialFilter,
|
|
211
221
|
}: CategoryRequestOptions): Promise<CategoryResponse> {
|
|
212
|
-
|
|
222
|
+
const filteredFeatures = this._getFilteredFeatures(
|
|
223
|
+
spatialFilter,
|
|
224
|
+
filters,
|
|
225
|
+
filterOwner
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
if (!filteredFeatures.length) {
|
|
213
229
|
return [];
|
|
214
230
|
}
|
|
215
231
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
assertColumn(this._features, column as string, operationColumn as string);
|
|
232
|
+
assertColumn(this._features, column, operationColumn as string);
|
|
219
233
|
|
|
220
234
|
const groups = groupValuesByColumn({
|
|
221
235
|
data: filteredFeatures,
|
|
@@ -233,14 +247,20 @@ export class WidgetTilesetSource<
|
|
|
233
247
|
yAxisColumn,
|
|
234
248
|
xAxisJoinOperation,
|
|
235
249
|
yAxisJoinOperation,
|
|
250
|
+
filters,
|
|
236
251
|
filterOwner,
|
|
252
|
+
spatialFilter,
|
|
237
253
|
}: ScatterRequestOptions): Promise<ScatterResponse> {
|
|
238
|
-
|
|
254
|
+
const filteredFeatures = this._getFilteredFeatures(
|
|
255
|
+
spatialFilter,
|
|
256
|
+
filters,
|
|
257
|
+
filterOwner
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
if (!filteredFeatures.length) {
|
|
239
261
|
return [];
|
|
240
262
|
}
|
|
241
263
|
|
|
242
|
-
const filteredFeatures = this._getFilteredFeatures(filterOwner);
|
|
243
|
-
|
|
244
264
|
assertColumn(this._features, xAxisColumn, yAxisColumn);
|
|
245
265
|
|
|
246
266
|
return scatterPlot({
|
|
@@ -252,35 +272,36 @@ export class WidgetTilesetSource<
|
|
|
252
272
|
});
|
|
253
273
|
}
|
|
254
274
|
|
|
255
|
-
override async getTable(
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
275
|
+
override async getTable({
|
|
276
|
+
columns,
|
|
277
|
+
searchFilterColumn,
|
|
278
|
+
searchFilterText,
|
|
279
|
+
sortBy,
|
|
280
|
+
sortDirection,
|
|
281
|
+
sortByColumnType,
|
|
282
|
+
offset = 0,
|
|
283
|
+
limit = 10,
|
|
284
|
+
filters,
|
|
285
|
+
filterOwner,
|
|
286
|
+
spatialFilter,
|
|
287
|
+
}: TableRequestOptions): Promise<TableResponse> {
|
|
288
|
+
// Filter.
|
|
289
|
+
let filteredFeatures = this._getFilteredFeatures(
|
|
290
|
+
spatialFilter,
|
|
291
|
+
filters,
|
|
292
|
+
filterOwner
|
|
293
|
+
);
|
|
269
294
|
|
|
270
|
-
if (!
|
|
295
|
+
if (!filteredFeatures.length) {
|
|
271
296
|
return {rows: [], totalCount: 0};
|
|
272
297
|
}
|
|
273
298
|
|
|
274
|
-
// Filter.
|
|
275
|
-
let filteredFeatures = this._getFilteredFeatures(filterOwner);
|
|
276
|
-
|
|
277
299
|
// Search.
|
|
278
|
-
// TODO: Could we get the same behavior by applying filters in loadTiles()?
|
|
279
300
|
if (searchFilterColumn && searchFilterText) {
|
|
280
301
|
filteredFeatures = filteredFeatures.filter(
|
|
281
302
|
(row) =>
|
|
282
303
|
row[searchFilterColumn] &&
|
|
283
|
-
String(row[searchFilterColumn])
|
|
304
|
+
String(row[searchFilterColumn] as unknown)
|
|
284
305
|
.toLowerCase()
|
|
285
306
|
.includes(String(searchFilterText).toLowerCase())
|
|
286
307
|
);
|
|
@@ -318,15 +339,21 @@ export class WidgetTilesetSource<
|
|
|
318
339
|
operation,
|
|
319
340
|
operationColumn,
|
|
320
341
|
joinOperation,
|
|
342
|
+
filters,
|
|
321
343
|
filterOwner,
|
|
344
|
+
spatialFilter,
|
|
322
345
|
}: TimeSeriesRequestOptions): Promise<TimeSeriesResponse> {
|
|
323
|
-
|
|
346
|
+
const filteredFeatures = this._getFilteredFeatures(
|
|
347
|
+
spatialFilter,
|
|
348
|
+
filters,
|
|
349
|
+
filterOwner
|
|
350
|
+
);
|
|
351
|
+
|
|
352
|
+
if (!filteredFeatures.length) {
|
|
324
353
|
return {rows: []};
|
|
325
354
|
}
|
|
326
355
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
assertColumn(this._features, column as string, operationColumn as string);
|
|
356
|
+
assertColumn(this._features, column, operationColumn as string);
|
|
330
357
|
|
|
331
358
|
const rows =
|
|
332
359
|
groupValuesByDateColumn({
|
|
@@ -343,17 +370,24 @@ export class WidgetTilesetSource<
|
|
|
343
370
|
|
|
344
371
|
override async getRange({
|
|
345
372
|
column,
|
|
373
|
+
filters,
|
|
346
374
|
filterOwner,
|
|
375
|
+
spatialFilter,
|
|
347
376
|
}: RangeRequestOptions): Promise<RangeResponse> {
|
|
377
|
+
assertColumn(this._features, column);
|
|
378
|
+
|
|
379
|
+
const filteredFeatures = this._getFilteredFeatures(
|
|
380
|
+
spatialFilter,
|
|
381
|
+
filters,
|
|
382
|
+
filterOwner
|
|
383
|
+
);
|
|
384
|
+
|
|
348
385
|
if (!this._features.length) {
|
|
349
386
|
// TODO: Is this the only nullable response in the Widgets API? If so,
|
|
350
387
|
// can we do something more consistent?
|
|
351
388
|
return null;
|
|
352
389
|
}
|
|
353
390
|
|
|
354
|
-
assertColumn(this._features, column);
|
|
355
|
-
|
|
356
|
-
const filteredFeatures = this._getFilteredFeatures(filterOwner);
|
|
357
391
|
return {
|
|
358
392
|
min: aggregationFunctions.min(filteredFeatures, column),
|
|
359
393
|
max: aggregationFunctions.max(filteredFeatures, column),
|
|
@@ -364,10 +398,16 @@ export class WidgetTilesetSource<
|
|
|
364
398
|
* INTERNAL
|
|
365
399
|
*/
|
|
366
400
|
|
|
367
|
-
private _getFilteredFeatures(
|
|
401
|
+
private _getFilteredFeatures(
|
|
402
|
+
spatialFilter?: SpatialFilter,
|
|
403
|
+
filters?: Record<string, Filter>,
|
|
404
|
+
filterOwner?: string
|
|
405
|
+
): FeatureData[] {
|
|
406
|
+
assert(spatialFilter, 'spatialFilter required for tilesets');
|
|
407
|
+
this._extractTileFeatures(spatialFilter);
|
|
368
408
|
return applyFilters(
|
|
369
409
|
this._features,
|
|
370
|
-
getApplicableFilters(filterOwner, this.props.filters),
|
|
410
|
+
getApplicableFilters(filterOwner, filters || this.props.filters),
|
|
371
411
|
this.props.filtersLogicalOperator || 'and'
|
|
372
412
|
);
|
|
373
413
|
}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CategoryRequestOptions,
|
|
3
|
+
CategoryResponse,
|
|
4
|
+
FeaturesResponse,
|
|
5
|
+
FormulaRequestOptions,
|
|
6
|
+
FormulaResponse,
|
|
7
|
+
HistogramRequestOptions,
|
|
8
|
+
HistogramResponse,
|
|
9
|
+
RangeRequestOptions,
|
|
10
|
+
RangeResponse,
|
|
11
|
+
ScatterRequestOptions,
|
|
12
|
+
ScatterResponse,
|
|
13
|
+
TableRequestOptions,
|
|
14
|
+
TableResponse,
|
|
15
|
+
TimeSeriesRequestOptions,
|
|
16
|
+
TimeSeriesResponse,
|
|
17
|
+
} from './types.js';
|
|
18
|
+
import {SpatialFilter, Tile} from '../types.js';
|
|
19
|
+
import {TileFeatureExtractOptions} from '../filters/index.js';
|
|
20
|
+
import {FeatureCollection} from 'geojson';
|
|
21
|
+
import {WidgetSource} from './widget-source.js';
|
|
22
|
+
import {WidgetTilesetSourceProps} from './widget-tileset-source.js';
|
|
23
|
+
import {Method} from '../workers/constants.js';
|
|
24
|
+
import {WorkerRequest, WorkerResponse} from '../workers/types.js';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* TODO
|
|
28
|
+
*/
|
|
29
|
+
export class WidgetTilesetWorkerSource extends WidgetSource<WidgetTilesetSourceProps> {
|
|
30
|
+
constructor(props: WidgetTilesetSourceProps) {
|
|
31
|
+
super(props);
|
|
32
|
+
|
|
33
|
+
WidgetTilesetWorkerSource.init();
|
|
34
|
+
WidgetTilesetWorkerSource.WORKER.postMessage({
|
|
35
|
+
tableName: this.props.tableName,
|
|
36
|
+
method: Method.INIT,
|
|
37
|
+
params: [this.props],
|
|
38
|
+
} as WorkerRequest);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Loads features as a list of tiles (typically provided by deck.gl).
|
|
43
|
+
* After tiles are loaded, {@link extractTileFeatures} must be called
|
|
44
|
+
* before computing statistics on the tiles.
|
|
45
|
+
*/
|
|
46
|
+
loadTiles(tiles: unknown[]) {
|
|
47
|
+
tiles = (tiles as Tile[]).map(({id, bbox, data}) => ({
|
|
48
|
+
id,
|
|
49
|
+
bbox,
|
|
50
|
+
data,
|
|
51
|
+
}));
|
|
52
|
+
|
|
53
|
+
WidgetTilesetWorkerSource.WORKER.postMessage({
|
|
54
|
+
tableName: this.props.tableName,
|
|
55
|
+
method: Method.LOAD_TILES,
|
|
56
|
+
params: [tiles],
|
|
57
|
+
} as WorkerRequest);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Configures options used to extract features from tiles. */
|
|
61
|
+
setTileFeatureExtractOptions(options: TileFeatureExtractOptions) {
|
|
62
|
+
WidgetTilesetWorkerSource.WORKER.postMessage({
|
|
63
|
+
tableName: this.props.tableName,
|
|
64
|
+
type: Method.SET_TILE_FEATURE_EXTRACT_OPTIONS,
|
|
65
|
+
params: [options],
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Loads features as GeoJSON (used for testing).
|
|
71
|
+
* @experimental
|
|
72
|
+
* @internal Not for public use. Spatial filters in other method calls will be ignored.
|
|
73
|
+
*/
|
|
74
|
+
loadGeoJSON({
|
|
75
|
+
geojson,
|
|
76
|
+
spatialFilter,
|
|
77
|
+
}: {
|
|
78
|
+
geojson: FeatureCollection;
|
|
79
|
+
spatialFilter: SpatialFilter;
|
|
80
|
+
}) {
|
|
81
|
+
WidgetTilesetWorkerSource.WORKER.postMessage({
|
|
82
|
+
tableName: this.props.tableName,
|
|
83
|
+
method: Method.LOAD_GEOJSON,
|
|
84
|
+
params: [{geojson, spatialFilter}],
|
|
85
|
+
} as WorkerRequest);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
89
|
+
override async getFeatures(): Promise<FeaturesResponse> {
|
|
90
|
+
throw new Error('getFeatures not supported for tilesets');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async getFormula({
|
|
94
|
+
abortController,
|
|
95
|
+
...options
|
|
96
|
+
}: FormulaRequestOptions): Promise<FormulaResponse> {
|
|
97
|
+
return this._executeWorkerMethod(
|
|
98
|
+
this.props.tableName,
|
|
99
|
+
Method.GET_FORMULA,
|
|
100
|
+
[options],
|
|
101
|
+
abortController?.signal
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
override async getHistogram({
|
|
106
|
+
abortController,
|
|
107
|
+
...options
|
|
108
|
+
}: HistogramRequestOptions): Promise<HistogramResponse> {
|
|
109
|
+
return this._executeWorkerMethod(
|
|
110
|
+
this.props.tableName,
|
|
111
|
+
Method.GET_HISTOGRAM,
|
|
112
|
+
[options],
|
|
113
|
+
abortController?.signal
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
override async getCategories({
|
|
118
|
+
abortController,
|
|
119
|
+
...options
|
|
120
|
+
}: CategoryRequestOptions): Promise<CategoryResponse> {
|
|
121
|
+
return this._executeWorkerMethod(
|
|
122
|
+
this.props.tableName,
|
|
123
|
+
Method.GET_CATEGORIES,
|
|
124
|
+
[options],
|
|
125
|
+
abortController?.signal
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
override async getScatter({
|
|
130
|
+
abortController,
|
|
131
|
+
...options
|
|
132
|
+
}: ScatterRequestOptions): Promise<ScatterResponse> {
|
|
133
|
+
return this._executeWorkerMethod(
|
|
134
|
+
this.props.tableName,
|
|
135
|
+
Method.GET_SCATTER,
|
|
136
|
+
[options],
|
|
137
|
+
abortController?.signal
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
override async getTable({
|
|
142
|
+
abortController,
|
|
143
|
+
...options
|
|
144
|
+
}: TableRequestOptions): Promise<TableResponse> {
|
|
145
|
+
return this._executeWorkerMethod(
|
|
146
|
+
this.props.tableName,
|
|
147
|
+
Method.GET_TABLE,
|
|
148
|
+
[options],
|
|
149
|
+
abortController?.signal
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
override async getTimeSeries({
|
|
154
|
+
abortController,
|
|
155
|
+
...options
|
|
156
|
+
}: TimeSeriesRequestOptions): Promise<TimeSeriesResponse> {
|
|
157
|
+
return this._executeWorkerMethod(
|
|
158
|
+
this.props.tableName,
|
|
159
|
+
Method.GET_TIME_SERIES,
|
|
160
|
+
[options],
|
|
161
|
+
abortController?.signal
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
override async getRange({
|
|
166
|
+
abortController,
|
|
167
|
+
...options
|
|
168
|
+
}: RangeRequestOptions): Promise<RangeResponse> {
|
|
169
|
+
return this._executeWorkerMethod(
|
|
170
|
+
this.props.tableName,
|
|
171
|
+
Method.GET_RANGE,
|
|
172
|
+
[options],
|
|
173
|
+
abortController?.signal
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/////////////////////////////////////////////////////////////////////////////
|
|
178
|
+
// WEB WORKER MANAGEMENT
|
|
179
|
+
|
|
180
|
+
// TODO: Singleton? Pool shared among datasets? One per dataset?
|
|
181
|
+
protected static WORKER: Worker;
|
|
182
|
+
protected static _nextRequestID = 1;
|
|
183
|
+
|
|
184
|
+
static init() {
|
|
185
|
+
WidgetTilesetWorkerSource.WORKER = new Worker(
|
|
186
|
+
new URL('@carto/api-client/worker', import.meta.url),
|
|
187
|
+
{
|
|
188
|
+
type: 'module',
|
|
189
|
+
name: 'cartowidgettileset',
|
|
190
|
+
}
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
_executeWorkerMethod<T>(
|
|
195
|
+
tableName: string,
|
|
196
|
+
method: Method,
|
|
197
|
+
params: unknown[],
|
|
198
|
+
signal?: AbortSignal
|
|
199
|
+
): Promise<T> {
|
|
200
|
+
const worker = WidgetTilesetWorkerSource.WORKER;
|
|
201
|
+
const requestId = WidgetTilesetWorkerSource._nextRequestID++;
|
|
202
|
+
|
|
203
|
+
// TODO: ViewState may contain non-serializable data, which we do not need.
|
|
204
|
+
// Remove this sanitization after sc-469614 is fixed.
|
|
205
|
+
const options = params[0] as any;
|
|
206
|
+
if (options?.spatialIndexReferenceViewState) {
|
|
207
|
+
const {zoom, latitude, longitude} =
|
|
208
|
+
options.spatialIndexReferenceViewState;
|
|
209
|
+
options.spatialIndexReferenceViewState = {zoom, latitude, longitude};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
worker.postMessage({
|
|
213
|
+
requestId,
|
|
214
|
+
tableName,
|
|
215
|
+
method,
|
|
216
|
+
params,
|
|
217
|
+
} as WorkerRequest);
|
|
218
|
+
|
|
219
|
+
return new Promise((resolve, reject) => {
|
|
220
|
+
function listener(e: MessageEvent) {
|
|
221
|
+
const response = e.data as WorkerResponse;
|
|
222
|
+
if (response.requestId !== requestId) return;
|
|
223
|
+
|
|
224
|
+
worker.removeEventListener('message', listener);
|
|
225
|
+
|
|
226
|
+
if (signal?.aborted) {
|
|
227
|
+
reject(new Error(signal.reason));
|
|
228
|
+
} else if (response.ok) {
|
|
229
|
+
resolve(response.result as T);
|
|
230
|
+
} else {
|
|
231
|
+
reject(new Error(response.error));
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
worker.addEventListener('message', listener);
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export enum Method {
|
|
2
|
+
INIT = 'init',
|
|
3
|
+
LOAD_TILES = 'loadTiles',
|
|
4
|
+
SET_TILE_FEATURE_EXTRACT_OPTIONS = 'setTileFeatureExtractOptions',
|
|
5
|
+
LOAD_GEOJSON = 'loadGeoJSON',
|
|
6
|
+
GET_FORMULA = 'getFormula',
|
|
7
|
+
GET_HISTOGRAM = 'getHistogram',
|
|
8
|
+
GET_CATEGORIES = 'getCategories',
|
|
9
|
+
GET_SCATTER = 'getScatter',
|
|
10
|
+
GET_TABLE = 'getTable',
|
|
11
|
+
GET_TIME_SERIES = 'getTimeSeries',
|
|
12
|
+
GET_RANGE = 'getRange',
|
|
13
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type {Method} from './constants.js';
|
|
2
|
+
|
|
3
|
+
export type WorkerRequest = {
|
|
4
|
+
requestId?: number;
|
|
5
|
+
tableName: string; // TODO: Table name is not a unique identifier.
|
|
6
|
+
method: Method;
|
|
7
|
+
params: unknown[];
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type WorkerResponse =
|
|
11
|
+
| {
|
|
12
|
+
requestId: number;
|
|
13
|
+
ok: true;
|
|
14
|
+
result: unknown;
|
|
15
|
+
}
|
|
16
|
+
| {
|
|
17
|
+
requestId: number;
|
|
18
|
+
ok: false;
|
|
19
|
+
error: string;
|
|
20
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
let _isModuleWorkerSupported: boolean | null =
|
|
2
|
+
TSUP_FORMAT === 'cjs' ? false : null;
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Checks whether current environment supports ES Module Workers, by way of a
|
|
6
|
+
* two-part check:
|
|
7
|
+
* (1) If this is a CJS build, return false.
|
|
8
|
+
* (2) If this is an ESM build, return true if the runtime supports ESM Workers.
|
|
9
|
+
*/
|
|
10
|
+
export function isModuleWorkerSupported(): boolean {
|
|
11
|
+
if (_isModuleWorkerSupported !== null) {
|
|
12
|
+
return _isModuleWorkerSupported;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
// https://stackoverflow.com/a/62963963
|
|
17
|
+
new Worker('blob://', {
|
|
18
|
+
get type() {
|
|
19
|
+
_isModuleWorkerSupported = true;
|
|
20
|
+
return 'module' as const;
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
} catch {
|
|
24
|
+
// Do nothing. 'blob://' should always throw an error to prevent the
|
|
25
|
+
// browser from creating an (expensive) worker. We care whether the
|
|
26
|
+
// 'type' getter was called, not about the error.
|
|
27
|
+
} finally {
|
|
28
|
+
// If 'type' getter wasn't called, modules are unsupported.
|
|
29
|
+
_isModuleWorkerSupported ||= false;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return _isModuleWorkerSupported;
|
|
33
|
+
}
|