@carto/api-client 0.5.0-alpha.1 → 0.5.0-alpha.11
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 +3163 -3206
- package/build/api-client.cjs.map +1 -1
- package/build/api-client.d.cts +1389 -0
- package/build/api-client.d.ts +1389 -0
- package/build/api-client.js +3674 -0
- package/build/api-client.js.map +1 -0
- package/build/worker.d.ts +2 -0
- package/build/worker.js +1949 -0
- package/build/worker.js.map +1 -0
- package/package.json +60 -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 +12 -17
- package/src/filters.ts +4 -4
- package/src/geo.ts +12 -14
- package/src/global.d.ts +3 -8
- package/src/index.ts +3 -0
- package/src/models/common.ts +11 -9
- 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 +2 -2
- package/src/sources/types.ts +9 -3
- 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 +15 -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 +6 -4
- package/src/widget-sources/widget-query-source.ts +6 -2
- package/src/widget-sources/widget-remote-source.ts +67 -26
- package/src/widget-sources/widget-source.ts +10 -25
- package/src/widget-sources/widget-table-source.ts +6 -2
- package/src/widget-sources/widget-tileset-source-impl.ts +417 -0
- package/src/widget-sources/widget-tileset-source.ts +200 -299
- package/src/workers/constants.ts +13 -0
- package/src/workers/types.ts +19 -0
- package/src/workers/widget-tileset-worker.ts +40 -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.modern.js +0 -3574
- 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 -20
- package/build/filters/tileFeaturesGeometries.d.ts +0 -13
- 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 -14
- 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 -4
- 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 -8
- package/build/types-internal.d.ts +0 -56
- package/build/types.d.ts +0 -140
- 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 -5
- 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-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 -76
|
@@ -1,3574 +0,0 @@
|
|
|
1
|
-
import bboxClip from '@turf/bbox-clip';
|
|
2
|
-
import bboxPolygon from '@turf/bbox-polygon';
|
|
3
|
-
import union from '@turf/union';
|
|
4
|
-
import { getType } from '@turf/invariant';
|
|
5
|
-
import { featureCollection, feature, polygon, multiPolygon } from '@turf/helpers';
|
|
6
|
-
import intersects from '@turf/boolean-intersects';
|
|
7
|
-
import booleanWithin from '@turf/boolean-within';
|
|
8
|
-
import intersect from '@turf/intersect';
|
|
9
|
-
import { getResolution as getResolution$2, polygonToCells } from 'h3-js';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* @internal
|
|
13
|
-
* @internalRemarks Source: @carto/react-core, @carto/constants, @deck.gl/carto
|
|
14
|
-
*/
|
|
15
|
-
let client = 'deck-gl-carto';
|
|
16
|
-
/**
|
|
17
|
-
* Returns current client ID, used to categorize API requests. For internal use only.
|
|
18
|
-
*
|
|
19
|
-
* @internal
|
|
20
|
-
* @internalRemarks Source: @carto/react-core
|
|
21
|
-
*/
|
|
22
|
-
function getClient() {
|
|
23
|
-
return client;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Sets current client ID, used to categorize API requests. For internal use only.
|
|
27
|
-
*
|
|
28
|
-
* @internal
|
|
29
|
-
* @internalRemarks Source: @carto/react-core
|
|
30
|
-
*/
|
|
31
|
-
function setClient(c) {
|
|
32
|
-
client = c;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Defines a comparator used when matching a column's values against given filter values.
|
|
37
|
-
*
|
|
38
|
-
* Example:
|
|
39
|
-
*
|
|
40
|
-
* ```javascript
|
|
41
|
-
* import { FilterType } from '@carto/api-client';
|
|
42
|
-
* const filters = {
|
|
43
|
-
* column_name: { [FilterType.IN]: { values: ['a', 'b', 'c'] } }
|
|
44
|
-
* };
|
|
45
|
-
* ```
|
|
46
|
-
*
|
|
47
|
-
* @internalRemarks Source: @carto/react-api, @deck.gl/carto
|
|
48
|
-
*/
|
|
49
|
-
var FilterType;
|
|
50
|
-
(function (FilterType) {
|
|
51
|
-
FilterType["IN"] = "in";
|
|
52
|
-
/** [a, b] both are included. */
|
|
53
|
-
FilterType["BETWEEN"] = "between";
|
|
54
|
-
/** [a, b) a is included, b is not. */
|
|
55
|
-
FilterType["CLOSED_OPEN"] = "closed_open";
|
|
56
|
-
FilterType["TIME"] = "time";
|
|
57
|
-
FilterType["STRING_SEARCH"] = "stringSearch";
|
|
58
|
-
})(FilterType || (FilterType = {}));
|
|
59
|
-
/** @internalRemarks Source: @carto/constants */
|
|
60
|
-
var ApiVersion;
|
|
61
|
-
(function (ApiVersion) {
|
|
62
|
-
ApiVersion["V1"] = "v1";
|
|
63
|
-
ApiVersion["V2"] = "v2";
|
|
64
|
-
ApiVersion["V3"] = "v3";
|
|
65
|
-
})(ApiVersion || (ApiVersion = {}));
|
|
66
|
-
/** @internalRemarks Source: @carto/constants, @deck.gl/carto */
|
|
67
|
-
const DEFAULT_API_BASE_URL = 'https://gcp-us-east1.api.carto.com';
|
|
68
|
-
/** @internalRemarks Source: @carto/react-core */
|
|
69
|
-
var TileFormat;
|
|
70
|
-
(function (TileFormat) {
|
|
71
|
-
TileFormat["MVT"] = "mvt";
|
|
72
|
-
TileFormat["JSON"] = "json";
|
|
73
|
-
TileFormat["GEOJSON"] = "geojson";
|
|
74
|
-
TileFormat["BINARY"] = "binary";
|
|
75
|
-
})(TileFormat || (TileFormat = {}));
|
|
76
|
-
/** @internalRemarks Source: @carto/react-core */
|
|
77
|
-
var SpatialIndex;
|
|
78
|
-
(function (SpatialIndex) {
|
|
79
|
-
SpatialIndex["H3"] = "h3";
|
|
80
|
-
SpatialIndex["S2"] = "s2";
|
|
81
|
-
SpatialIndex["QUADBIN"] = "quadbin";
|
|
82
|
-
})(SpatialIndex || (SpatialIndex = {}));
|
|
83
|
-
/** @internalRemarks Source: @carto/react-core */
|
|
84
|
-
var Provider;
|
|
85
|
-
(function (Provider) {
|
|
86
|
-
Provider["BIGQUERY"] = "bigquery";
|
|
87
|
-
Provider["REDSHIFT"] = "redshift";
|
|
88
|
-
Provider["POSTGRES"] = "postgres";
|
|
89
|
-
Provider["SNOWFLAKE"] = "snowflake";
|
|
90
|
-
Provider["DATABRICKS"] = "databricks";
|
|
91
|
-
Provider["DATABRICKS_REST"] = "databricksRest";
|
|
92
|
-
})(Provider || (Provider = {}));
|
|
93
|
-
|
|
94
|
-
const FILTER_TYPES = new Set(Object.values(FilterType));
|
|
95
|
-
const isFilterType = type => FILTER_TYPES.has(type);
|
|
96
|
-
/**
|
|
97
|
-
* @privateRemarks Source: @carto/react-widgets
|
|
98
|
-
* @internal
|
|
99
|
-
*/
|
|
100
|
-
function getApplicableFilters(owner, filters) {
|
|
101
|
-
if (!filters) return {};
|
|
102
|
-
const applicableFilters = {};
|
|
103
|
-
for (const column in filters) {
|
|
104
|
-
for (const type in filters[column]) {
|
|
105
|
-
if (!isFilterType(type)) continue;
|
|
106
|
-
const filter = filters[column][type];
|
|
107
|
-
const isApplicable = !owner || !(filter != null && filter.owner) || (filter == null ? void 0 : filter.owner) !== owner;
|
|
108
|
-
if (filter && isApplicable) {
|
|
109
|
-
applicableFilters[column] || (applicableFilters[column] = {});
|
|
110
|
-
applicableFilters[column][type] = filter;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return applicableFilters;
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* Due to each data warehouse having its own behavior with columns,
|
|
118
|
-
* we need to normalize them and transform every key to lowercase.
|
|
119
|
-
*
|
|
120
|
-
* @internalRemarks Source: @carto/react-widgets
|
|
121
|
-
* @internal
|
|
122
|
-
*/
|
|
123
|
-
function normalizeObjectKeys(el) {
|
|
124
|
-
if (Array.isArray(el)) {
|
|
125
|
-
return el.map(value => normalizeObjectKeys(value));
|
|
126
|
-
} else if (typeof el !== 'object') {
|
|
127
|
-
return el;
|
|
128
|
-
}
|
|
129
|
-
return Object.entries(el).reduce((acc, [key, value]) => {
|
|
130
|
-
acc[key.toLowerCase()] = typeof value === 'object' && value ? normalizeObjectKeys(value) : value;
|
|
131
|
-
return acc;
|
|
132
|
-
}, {});
|
|
133
|
-
}
|
|
134
|
-
/** @internalRemarks Source: @carto/react-core */
|
|
135
|
-
function assert$1(condition, message) {
|
|
136
|
-
if (!condition) {
|
|
137
|
-
throw new Error(message);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* @internalRemarks Source: @carto/react-core
|
|
142
|
-
* @internal
|
|
143
|
-
*/
|
|
144
|
-
class InvalidColumnError extends Error {
|
|
145
|
-
constructor(message) {
|
|
146
|
-
super(`${InvalidColumnError.NAME}: ${message}`);
|
|
147
|
-
this.name = InvalidColumnError.NAME;
|
|
148
|
-
}
|
|
149
|
-
static is(error) {
|
|
150
|
-
var _error$message;
|
|
151
|
-
return error instanceof InvalidColumnError || ((_error$message = error.message) == null ? void 0 : _error$message.includes(InvalidColumnError.NAME));
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
InvalidColumnError.NAME = 'InvalidColumnError';
|
|
155
|
-
function isEmptyObject(object) {
|
|
156
|
-
for (const _ in object) {
|
|
157
|
-
return false;
|
|
158
|
-
}
|
|
159
|
-
return true;
|
|
160
|
-
}
|
|
161
|
-
/** @internal */
|
|
162
|
-
const isObject = x => x !== null && typeof x === 'object';
|
|
163
|
-
/** @internal */
|
|
164
|
-
const isPureObject = x => isObject(x) && x.constructor === {}.constructor;
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Adds a {@link Filter} to the filter set. Any previous filters with the same
|
|
168
|
-
* `column` and `type` will be replaced.
|
|
169
|
-
*/
|
|
170
|
-
function addFilter(filters, {
|
|
171
|
-
column,
|
|
172
|
-
type,
|
|
173
|
-
values,
|
|
174
|
-
owner
|
|
175
|
-
}) {
|
|
176
|
-
if (!filters[column]) {
|
|
177
|
-
filters[column] = {};
|
|
178
|
-
}
|
|
179
|
-
const filter = {
|
|
180
|
-
values,
|
|
181
|
-
owner
|
|
182
|
-
};
|
|
183
|
-
filters[column][type] = filter;
|
|
184
|
-
return filters;
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* Removes one or more {@link Filter filters} from the filter set. If only
|
|
188
|
-
* `column` is specified, then all filters on that column are removed. If both
|
|
189
|
-
* `column` and `owner` are specified, then only filters for that column
|
|
190
|
-
* associated with the owner are removed.
|
|
191
|
-
*/
|
|
192
|
-
function removeFilter(filters, {
|
|
193
|
-
column,
|
|
194
|
-
owner
|
|
195
|
-
}) {
|
|
196
|
-
const filter = filters[column];
|
|
197
|
-
if (!filter) {
|
|
198
|
-
return filters;
|
|
199
|
-
}
|
|
200
|
-
if (owner) {
|
|
201
|
-
for (const type of Object.values(FilterType)) {
|
|
202
|
-
var _filter$type;
|
|
203
|
-
if (owner === ((_filter$type = filter[type]) == null ? void 0 : _filter$type.owner)) {
|
|
204
|
-
delete filter[type];
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
if (!owner || isEmptyObject(filter)) {
|
|
209
|
-
delete filters[column];
|
|
210
|
-
}
|
|
211
|
-
return filters;
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* Clears all {@link Filter filters} from the filter set.
|
|
215
|
-
*/
|
|
216
|
-
function clearFilters(filters) {
|
|
217
|
-
for (const column of Object.keys(filters)) {
|
|
218
|
-
delete filters[column];
|
|
219
|
-
}
|
|
220
|
-
return filters;
|
|
221
|
-
}
|
|
222
|
-
function hasFilter(filters, {
|
|
223
|
-
column,
|
|
224
|
-
owner
|
|
225
|
-
}) {
|
|
226
|
-
const filter = filters[column];
|
|
227
|
-
if (!filter) {
|
|
228
|
-
return false;
|
|
229
|
-
}
|
|
230
|
-
if (!owner) {
|
|
231
|
-
return true;
|
|
232
|
-
}
|
|
233
|
-
for (const type of Object.values(FilterType)) {
|
|
234
|
-
var _filter$type2;
|
|
235
|
-
if (owner === ((_filter$type2 = filter[type]) == null ? void 0 : _filter$type2.owner)) {
|
|
236
|
-
return true;
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
return false;
|
|
240
|
-
}
|
|
241
|
-
function getFilter(filters, {
|
|
242
|
-
column,
|
|
243
|
-
type,
|
|
244
|
-
owner
|
|
245
|
-
}) {
|
|
246
|
-
var _filter$type3;
|
|
247
|
-
const filter = filters[column];
|
|
248
|
-
if (!filter) {
|
|
249
|
-
return null;
|
|
250
|
-
}
|
|
251
|
-
if (!owner || owner === ((_filter$type3 = filter[type]) == null ? void 0 : _filter$type3.owner)) {
|
|
252
|
-
return filter[type] || null;
|
|
253
|
-
}
|
|
254
|
-
return null;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Returns a {@link SpatialFilter} for a given viewport, typically obtained
|
|
259
|
-
* from deck.gl's `viewport.getBounds()` method ([west, south, east, north]).
|
|
260
|
-
* If the viewport covers the entire world (to some margin of error in Web
|
|
261
|
-
* Mercator space), `undefined` is returned instead.
|
|
262
|
-
*
|
|
263
|
-
* If the viewport extends beyond longitude range [-180, +180], the polygon
|
|
264
|
-
* may be reformatted for compatibility with CARTO APIs.
|
|
265
|
-
*/
|
|
266
|
-
function createViewportSpatialFilter(viewport) {
|
|
267
|
-
if (_isGlobalViewport(viewport)) {
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
return createPolygonSpatialFilter(bboxPolygon(viewport).geometry);
|
|
271
|
-
}
|
|
272
|
-
/**
|
|
273
|
-
* Returns a {@link SpatialFilter} for a given {@link Polygon} or
|
|
274
|
-
* {@link MultiPolygon}. If the polygon(s) extend outside longitude
|
|
275
|
-
* range [-180, +180], the result may be reformatted for compatibility
|
|
276
|
-
* with CARTO APIs.
|
|
277
|
-
*/
|
|
278
|
-
function createPolygonSpatialFilter(spatialFilter) {
|
|
279
|
-
return spatialFilter && _normalizeGeometry(spatialFilter) || undefined;
|
|
280
|
-
}
|
|
281
|
-
/**
|
|
282
|
-
* Check if a viewport is large enough to represent a global coverage.
|
|
283
|
-
* In this case the spatial filter parameter for widget calculation is removed.
|
|
284
|
-
*
|
|
285
|
-
* @internalRemarks Source: @carto/react-core
|
|
286
|
-
*/
|
|
287
|
-
function _isGlobalViewport(viewport) {
|
|
288
|
-
const [minx, miny, maxx, maxy] = viewport;
|
|
289
|
-
return maxx - minx > 179.5 * 2 && maxy - miny > 85.05 * 2;
|
|
290
|
-
}
|
|
291
|
-
/**
|
|
292
|
-
* Normalized a geometry, coming from a mask or a viewport. The parts
|
|
293
|
-
* spanning outside longitude range [-180, +180] are clipped and "folded"
|
|
294
|
-
* back to the valid range and unioned to the polygons inide that range.
|
|
295
|
-
*
|
|
296
|
-
* It results in a Polygon or MultiPolygon strictly inside the validity range.
|
|
297
|
-
*
|
|
298
|
-
* @internalRemarks Source: @carto/react-core
|
|
299
|
-
*/
|
|
300
|
-
function _normalizeGeometry(geometry) {
|
|
301
|
-
const WORLD = [-180, -90, +180, +90];
|
|
302
|
-
const worldClip = _clean(bboxClip(geometry, WORLD).geometry);
|
|
303
|
-
const geometryTxWest = _tx(geometry, 360);
|
|
304
|
-
const geometryTxEast = _tx(geometry, -360);
|
|
305
|
-
let result = worldClip;
|
|
306
|
-
if (result && geometryTxWest) {
|
|
307
|
-
const worldWestClip = _clean(bboxClip(geometryTxWest, WORLD).geometry);
|
|
308
|
-
if (worldWestClip) {
|
|
309
|
-
const collection = featureCollection([feature(result), feature(worldWestClip)]);
|
|
310
|
-
const merged = union(collection);
|
|
311
|
-
result = merged ? _clean(merged.geometry) : result;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
if (result && geometryTxEast) {
|
|
315
|
-
const worldEastClip = _clean(bboxClip(geometryTxEast, WORLD).geometry);
|
|
316
|
-
if (worldEastClip) {
|
|
317
|
-
const collection = featureCollection([feature(result), feature(worldEastClip)]);
|
|
318
|
-
const merged = union(collection);
|
|
319
|
-
result = merged ? _clean(merged.geometry) : result;
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
return result;
|
|
323
|
-
}
|
|
324
|
-
/** @internalRemarks Source: @carto/react-core */
|
|
325
|
-
function _cleanPolygonCoords(cc) {
|
|
326
|
-
const coords = cc.filter(c => c.length > 0);
|
|
327
|
-
return coords.length > 0 ? coords : null;
|
|
328
|
-
}
|
|
329
|
-
/** @internalRemarks Source: @carto/react-core */
|
|
330
|
-
function _cleanMultiPolygonCoords(ccc) {
|
|
331
|
-
const coords = ccc.map(_cleanPolygonCoords).filter(cc => cc);
|
|
332
|
-
return coords.length > 0 ? coords : null;
|
|
333
|
-
}
|
|
334
|
-
/** @internalRemarks Source: @carto/react-core */
|
|
335
|
-
function _clean(geometry) {
|
|
336
|
-
if (!geometry) {
|
|
337
|
-
return null;
|
|
338
|
-
}
|
|
339
|
-
if (_isPolygon(geometry)) {
|
|
340
|
-
const coords = _cleanPolygonCoords(geometry.coordinates);
|
|
341
|
-
return coords ? polygon(coords).geometry : null;
|
|
342
|
-
}
|
|
343
|
-
if (_isMultiPolygon(geometry)) {
|
|
344
|
-
const coords = _cleanMultiPolygonCoords(geometry.coordinates);
|
|
345
|
-
return coords ? multiPolygon(coords).geometry : null;
|
|
346
|
-
}
|
|
347
|
-
return null;
|
|
348
|
-
}
|
|
349
|
-
/** @internalRemarks Source: @carto/react-core */
|
|
350
|
-
function _txContourCoords(cc, distance) {
|
|
351
|
-
return cc.map(c => [c[0] + distance, c[1]]);
|
|
352
|
-
}
|
|
353
|
-
/** @internalRemarks Source: @carto/react-core */
|
|
354
|
-
function _txPolygonCoords(ccc, distance) {
|
|
355
|
-
return ccc.map(cc => _txContourCoords(cc, distance));
|
|
356
|
-
}
|
|
357
|
-
/** @internalRemarks Source: @carto/react-core */
|
|
358
|
-
function _txMultiPolygonCoords(cccc, distance) {
|
|
359
|
-
return cccc.map(ccc => _txPolygonCoords(ccc, distance));
|
|
360
|
-
}
|
|
361
|
-
/** @internalRemarks Source: @carto/react-core */
|
|
362
|
-
function _tx(geometry, distance) {
|
|
363
|
-
if (geometry && getType(geometry) === 'Polygon') {
|
|
364
|
-
const coords = _txPolygonCoords(geometry.coordinates, distance);
|
|
365
|
-
return polygon(coords).geometry;
|
|
366
|
-
} else if (geometry && getType(geometry) === 'MultiPolygon') {
|
|
367
|
-
const coords = _txMultiPolygonCoords(geometry.coordinates, distance);
|
|
368
|
-
return multiPolygon(coords).geometry;
|
|
369
|
-
} else {
|
|
370
|
-
return null;
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
function _isPolygon(geometry) {
|
|
374
|
-
return getType(geometry) === 'Polygon';
|
|
375
|
-
}
|
|
376
|
-
function _isMultiPolygon(geometry) {
|
|
377
|
-
return getType(geometry) === 'MultiPolygon';
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
function _extends() {
|
|
381
|
-
return _extends = Object.assign ? Object.assign.bind() : function (n) {
|
|
382
|
-
for (var e = 1; e < arguments.length; e++) {
|
|
383
|
-
var t = arguments[e];
|
|
384
|
-
for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
|
|
385
|
-
}
|
|
386
|
-
return n;
|
|
387
|
-
}, _extends.apply(null, arguments);
|
|
388
|
-
}
|
|
389
|
-
function _objectWithoutPropertiesLoose(r, e) {
|
|
390
|
-
if (null == r) return {};
|
|
391
|
-
var t = {};
|
|
392
|
-
for (var n in r) if ({}.hasOwnProperty.call(r, n)) {
|
|
393
|
-
if (e.includes(n)) continue;
|
|
394
|
-
t[n] = r[n];
|
|
395
|
-
}
|
|
396
|
-
return t;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
/**
|
|
400
|
-
* Current version of @carto/api-client.
|
|
401
|
-
* @internal
|
|
402
|
-
*/
|
|
403
|
-
/** @internal */
|
|
404
|
-
const V3_MINOR_VERSION = '3.4';
|
|
405
|
-
/** @internalRemarks Source: @carto/constants, @deck.gl/carto */
|
|
406
|
-
const DEFAULT_GEO_COLUMN = 'geom';
|
|
407
|
-
/**
|
|
408
|
-
* Fastly default limit is 8192; leave some padding.
|
|
409
|
-
* @internalRemarks Source: @deck.gl/carto
|
|
410
|
-
*/
|
|
411
|
-
const DEFAULT_MAX_LENGTH_URL = 7000;
|
|
412
|
-
/** @internalRemarks Source: @deck.gl/carto */
|
|
413
|
-
const DEFAULT_TILE_RESOLUTION = 0.5;
|
|
414
|
-
/**
|
|
415
|
-
* @internalRemarks Source: @deck.gl/carto
|
|
416
|
-
* @internal
|
|
417
|
-
*/
|
|
418
|
-
const DEFAULT_AGGREGATION_RES_LEVEL_H3 = 4;
|
|
419
|
-
/**
|
|
420
|
-
* @internalRemarks Source: @deck.gl/carto
|
|
421
|
-
* @internal
|
|
422
|
-
*/
|
|
423
|
-
const DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN = 6;
|
|
424
|
-
|
|
425
|
-
// deck.gl
|
|
426
|
-
// SPDX-License-Identifier: MIT
|
|
427
|
-
// Copyright (c) vis.gl contributors
|
|
428
|
-
function joinPath(...args) {
|
|
429
|
-
return args.map(part => part.endsWith('/') ? part.slice(0, -1) : part).join('/');
|
|
430
|
-
}
|
|
431
|
-
function buildV3Path(apiBaseUrl, version, endpoint, ...rest) {
|
|
432
|
-
return joinPath(apiBaseUrl, version, endpoint, ...rest);
|
|
433
|
-
}
|
|
434
|
-
/** @internal Required by fetchMap(). */
|
|
435
|
-
function buildPublicMapUrl({
|
|
436
|
-
apiBaseUrl,
|
|
437
|
-
cartoMapId
|
|
438
|
-
}) {
|
|
439
|
-
return buildV3Path(apiBaseUrl, 'v3', 'maps', 'public', cartoMapId);
|
|
440
|
-
}
|
|
441
|
-
/** @internal Required by fetchMap(). */
|
|
442
|
-
function buildStatsUrl({
|
|
443
|
-
attribute,
|
|
444
|
-
apiBaseUrl,
|
|
445
|
-
connectionName,
|
|
446
|
-
source,
|
|
447
|
-
type
|
|
448
|
-
}) {
|
|
449
|
-
if (type === 'query') {
|
|
450
|
-
return buildV3Path(apiBaseUrl, 'v3', 'stats', connectionName, attribute);
|
|
451
|
-
}
|
|
452
|
-
// type === 'table'
|
|
453
|
-
return buildV3Path(apiBaseUrl, 'v3', 'stats', connectionName, source, attribute);
|
|
454
|
-
}
|
|
455
|
-
function buildSourceUrl({
|
|
456
|
-
apiBaseUrl,
|
|
457
|
-
connectionName,
|
|
458
|
-
endpoint
|
|
459
|
-
}) {
|
|
460
|
-
return buildV3Path(apiBaseUrl, 'v3', 'maps', connectionName, endpoint);
|
|
461
|
-
}
|
|
462
|
-
function buildQueryUrl({
|
|
463
|
-
apiBaseUrl,
|
|
464
|
-
connectionName
|
|
465
|
-
}) {
|
|
466
|
-
return buildV3Path(apiBaseUrl, 'v3', 'sql', connectionName, 'query');
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
// deck.gl
|
|
470
|
-
// SPDX-License-Identifier: MIT
|
|
471
|
-
// Copyright (c) vis.gl contributors
|
|
472
|
-
/**
|
|
473
|
-
*
|
|
474
|
-
* Custom error for reported errors in CARTO Maps API.
|
|
475
|
-
* Provides useful debugging information in console and context for applications.
|
|
476
|
-
*
|
|
477
|
-
*/
|
|
478
|
-
class CartoAPIError extends Error {
|
|
479
|
-
constructor(error, errorContext, response, responseJson) {
|
|
480
|
-
let responseString = 'Failed to connect';
|
|
481
|
-
if (response) {
|
|
482
|
-
responseString = 'Server returned: ';
|
|
483
|
-
if (response.status === 400) {
|
|
484
|
-
responseString += 'Bad request';
|
|
485
|
-
} else if (response.status === 401 || response.status === 403) {
|
|
486
|
-
responseString += 'Unauthorized access';
|
|
487
|
-
} else if (response.status === 404) {
|
|
488
|
-
responseString += 'Not found';
|
|
489
|
-
} else {
|
|
490
|
-
responseString += 'Error';
|
|
491
|
-
}
|
|
492
|
-
responseString += ` (${response.status}):`;
|
|
493
|
-
}
|
|
494
|
-
responseString += ` ${error.message || error}`;
|
|
495
|
-
let message = `${errorContext.requestType} API request failed`;
|
|
496
|
-
message += `\n${responseString}`;
|
|
497
|
-
for (const key of Object.keys(errorContext)) {
|
|
498
|
-
if (key === 'requestType') continue;
|
|
499
|
-
message += `\n${formatErrorKey(key)}: ${errorContext[key]}`;
|
|
500
|
-
}
|
|
501
|
-
message += '\n';
|
|
502
|
-
super(message);
|
|
503
|
-
/** Source error from server */
|
|
504
|
-
this.error = void 0;
|
|
505
|
-
/** Context (API call & parameters) in which error occured */
|
|
506
|
-
this.errorContext = void 0;
|
|
507
|
-
/** Response from server */
|
|
508
|
-
this.response = void 0;
|
|
509
|
-
/** JSON Response from server */
|
|
510
|
-
this.responseJson = void 0;
|
|
511
|
-
this.name = 'CartoAPIError';
|
|
512
|
-
this.response = response;
|
|
513
|
-
this.responseJson = responseJson;
|
|
514
|
-
this.error = error;
|
|
515
|
-
this.errorContext = errorContext;
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
/**
|
|
519
|
-
* Converts camelCase to Camel Case
|
|
520
|
-
*/
|
|
521
|
-
function formatErrorKey(key) {
|
|
522
|
-
return key.replace(/([A-Z])/g, ' $1').replace(/^./, s => s.toUpperCase());
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
const DEFAULT_HEADERS = {
|
|
526
|
-
Accept: 'application/json',
|
|
527
|
-
'Content-Type': 'application/json'
|
|
528
|
-
};
|
|
529
|
-
const DEFAULT_REQUEST_CACHE = new Map();
|
|
530
|
-
async function requestWithParameters({
|
|
531
|
-
baseUrl,
|
|
532
|
-
parameters = {},
|
|
533
|
-
headers: customHeaders = {},
|
|
534
|
-
errorContext,
|
|
535
|
-
maxLengthURL = DEFAULT_MAX_LENGTH_URL,
|
|
536
|
-
localCache
|
|
537
|
-
}) {
|
|
538
|
-
// Parameters added to all requests issued with `requestWithParameters()`.
|
|
539
|
-
// These parameters override parameters already in the base URL, but not
|
|
540
|
-
// user-provided parameters.
|
|
541
|
-
parameters = _extends({
|
|
542
|
-
v: V3_MINOR_VERSION,
|
|
543
|
-
client: getClient()
|
|
544
|
-
}, typeof deck !== 'undefined' && deck.VERSION && {
|
|
545
|
-
deckglVersion: deck.VERSION
|
|
546
|
-
}, parameters);
|
|
547
|
-
baseUrl = excludeURLParameters(baseUrl, Object.keys(parameters));
|
|
548
|
-
const key = createCacheKey(baseUrl, parameters, customHeaders);
|
|
549
|
-
const {
|
|
550
|
-
cache: REQUEST_CACHE,
|
|
551
|
-
canReadCache,
|
|
552
|
-
canStoreInCache
|
|
553
|
-
} = getCacheSettings(localCache);
|
|
554
|
-
if (canReadCache && REQUEST_CACHE.has(key)) {
|
|
555
|
-
return REQUEST_CACHE.get(key);
|
|
556
|
-
}
|
|
557
|
-
const url = createURLWithParameters(baseUrl, parameters);
|
|
558
|
-
const headers = _extends({}, DEFAULT_HEADERS, customHeaders);
|
|
559
|
-
/* global fetch */
|
|
560
|
-
const fetchPromise = url.length > maxLengthURL ? fetch(baseUrl, {
|
|
561
|
-
method: 'POST',
|
|
562
|
-
body: JSON.stringify(parameters),
|
|
563
|
-
headers
|
|
564
|
-
}) : fetch(url, {
|
|
565
|
-
headers
|
|
566
|
-
});
|
|
567
|
-
let response;
|
|
568
|
-
let responseJson;
|
|
569
|
-
const jsonPromise = fetchPromise.then(_response => {
|
|
570
|
-
response = _response;
|
|
571
|
-
return response.json();
|
|
572
|
-
}).then(json => {
|
|
573
|
-
responseJson = json;
|
|
574
|
-
if (!response || !response.ok) {
|
|
575
|
-
throw new Error(json.error);
|
|
576
|
-
}
|
|
577
|
-
return json;
|
|
578
|
-
}).catch(error => {
|
|
579
|
-
if (canStoreInCache) {
|
|
580
|
-
REQUEST_CACHE.delete(key);
|
|
581
|
-
}
|
|
582
|
-
throw new CartoAPIError(error, errorContext, response, responseJson);
|
|
583
|
-
});
|
|
584
|
-
if (canStoreInCache) {
|
|
585
|
-
REQUEST_CACHE.set(key, jsonPromise);
|
|
586
|
-
}
|
|
587
|
-
return jsonPromise;
|
|
588
|
-
}
|
|
589
|
-
function getCacheSettings(localCache) {
|
|
590
|
-
var _localCache$cacheCont, _localCache$cacheCont2;
|
|
591
|
-
const canReadCache = localCache != null && (_localCache$cacheCont = localCache.cacheControl) != null && _localCache$cacheCont.includes('no-cache') ? false : true;
|
|
592
|
-
const canStoreInCache = localCache != null && (_localCache$cacheCont2 = localCache.cacheControl) != null && _localCache$cacheCont2.includes('no-store') ? false : true;
|
|
593
|
-
const cache = (localCache == null ? void 0 : localCache.cache) || DEFAULT_REQUEST_CACHE;
|
|
594
|
-
return {
|
|
595
|
-
cache,
|
|
596
|
-
canReadCache,
|
|
597
|
-
canStoreInCache
|
|
598
|
-
};
|
|
599
|
-
}
|
|
600
|
-
function createCacheKey(baseUrl, parameters, headers) {
|
|
601
|
-
const parameterEntries = Object.entries(parameters).sort(([a], [b]) => a > b ? 1 : -1);
|
|
602
|
-
const headerEntries = Object.entries(headers).sort(([a], [b]) => a > b ? 1 : -1);
|
|
603
|
-
return JSON.stringify({
|
|
604
|
-
baseUrl,
|
|
605
|
-
parameters: parameterEntries,
|
|
606
|
-
headers: headerEntries
|
|
607
|
-
});
|
|
608
|
-
}
|
|
609
|
-
/**
|
|
610
|
-
* Appends query string parameters to a URL. Existing URL parameters are kept,
|
|
611
|
-
* unless there is a conflict, in which case the new parameters override
|
|
612
|
-
* those already in the URL.
|
|
613
|
-
*/
|
|
614
|
-
function createURLWithParameters(baseUrlString, parameters) {
|
|
615
|
-
const baseUrl = new URL(baseUrlString);
|
|
616
|
-
for (const [key, value] of Object.entries(parameters)) {
|
|
617
|
-
if (isPureObject(value) || Array.isArray(value)) {
|
|
618
|
-
baseUrl.searchParams.set(key, JSON.stringify(value));
|
|
619
|
-
} else {
|
|
620
|
-
baseUrl.searchParams.set(key, value.toString());
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
return baseUrl.toString();
|
|
624
|
-
}
|
|
625
|
-
/**
|
|
626
|
-
* Deletes query string parameters from a URL.
|
|
627
|
-
*/
|
|
628
|
-
function excludeURLParameters(baseUrlString, parameters) {
|
|
629
|
-
const baseUrl = new URL(baseUrlString);
|
|
630
|
-
for (const param of parameters) {
|
|
631
|
-
if (baseUrl.searchParams.has(param)) {
|
|
632
|
-
baseUrl.searchParams.delete(param);
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
return baseUrl.toString();
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
const _excluded$2 = ["accessToken", "connectionName", "cache"];
|
|
639
|
-
const SOURCE_DEFAULTS = {
|
|
640
|
-
apiBaseUrl: DEFAULT_API_BASE_URL,
|
|
641
|
-
clientId: getClient(),
|
|
642
|
-
format: 'tilejson',
|
|
643
|
-
headers: {},
|
|
644
|
-
maxLengthURL: DEFAULT_MAX_LENGTH_URL
|
|
645
|
-
};
|
|
646
|
-
async function baseSource(endpoint, options, urlParameters) {
|
|
647
|
-
const {
|
|
648
|
-
accessToken,
|
|
649
|
-
connectionName,
|
|
650
|
-
cache
|
|
651
|
-
} = options,
|
|
652
|
-
optionalOptions = _objectWithoutPropertiesLoose(options, _excluded$2);
|
|
653
|
-
const mergedOptions = _extends({}, SOURCE_DEFAULTS, {
|
|
654
|
-
accessToken,
|
|
655
|
-
connectionName,
|
|
656
|
-
endpoint
|
|
657
|
-
});
|
|
658
|
-
for (const key in optionalOptions) {
|
|
659
|
-
if (optionalOptions[key]) {
|
|
660
|
-
mergedOptions[key] = optionalOptions[key];
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
const baseUrl = buildSourceUrl(mergedOptions);
|
|
664
|
-
const {
|
|
665
|
-
clientId,
|
|
666
|
-
maxLengthURL,
|
|
667
|
-
format,
|
|
668
|
-
localCache
|
|
669
|
-
} = mergedOptions;
|
|
670
|
-
const headers = _extends({
|
|
671
|
-
Authorization: `Bearer ${options.accessToken}`
|
|
672
|
-
}, options.headers);
|
|
673
|
-
const parameters = _extends({
|
|
674
|
-
client: clientId
|
|
675
|
-
}, urlParameters);
|
|
676
|
-
const errorContext = {
|
|
677
|
-
requestType: 'Map instantiation',
|
|
678
|
-
connection: options.connectionName,
|
|
679
|
-
type: endpoint,
|
|
680
|
-
source: JSON.stringify(parameters, undefined, 2)
|
|
681
|
-
};
|
|
682
|
-
const mapInstantiation = await requestWithParameters({
|
|
683
|
-
baseUrl,
|
|
684
|
-
parameters,
|
|
685
|
-
headers,
|
|
686
|
-
errorContext,
|
|
687
|
-
maxLengthURL,
|
|
688
|
-
localCache
|
|
689
|
-
});
|
|
690
|
-
const dataUrl = mapInstantiation[format].url[0];
|
|
691
|
-
if (cache) {
|
|
692
|
-
cache.value = parseInt(new URL(dataUrl).searchParams.get('cache') || '', 10);
|
|
693
|
-
}
|
|
694
|
-
errorContext.requestType = 'Map data';
|
|
695
|
-
if (format === 'tilejson') {
|
|
696
|
-
const json = await requestWithParameters({
|
|
697
|
-
baseUrl: dataUrl,
|
|
698
|
-
headers,
|
|
699
|
-
errorContext,
|
|
700
|
-
maxLengthURL,
|
|
701
|
-
localCache
|
|
702
|
-
});
|
|
703
|
-
if (accessToken) {
|
|
704
|
-
json.accessToken = accessToken;
|
|
705
|
-
}
|
|
706
|
-
return json;
|
|
707
|
-
}
|
|
708
|
-
return await requestWithParameters({
|
|
709
|
-
baseUrl: dataUrl,
|
|
710
|
-
headers,
|
|
711
|
-
errorContext,
|
|
712
|
-
maxLengthURL,
|
|
713
|
-
localCache
|
|
714
|
-
});
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
// deck.gl
|
|
718
|
-
// SPDX-License-Identifier: MIT
|
|
719
|
-
// Copyright (c) vis.gl contributors
|
|
720
|
-
const boundaryQuerySource = async function boundaryQuerySource(options) {
|
|
721
|
-
const {
|
|
722
|
-
columns,
|
|
723
|
-
filters,
|
|
724
|
-
tilesetTableName,
|
|
725
|
-
propertiesSqlQuery,
|
|
726
|
-
queryParameters
|
|
727
|
-
} = options;
|
|
728
|
-
const urlParameters = {
|
|
729
|
-
tilesetTableName,
|
|
730
|
-
propertiesSqlQuery
|
|
731
|
-
};
|
|
732
|
-
if (columns) {
|
|
733
|
-
urlParameters.columns = columns.join(',');
|
|
734
|
-
}
|
|
735
|
-
if (filters) {
|
|
736
|
-
urlParameters.filters = filters;
|
|
737
|
-
}
|
|
738
|
-
if (queryParameters) {
|
|
739
|
-
urlParameters.queryParameters = queryParameters;
|
|
740
|
-
}
|
|
741
|
-
return baseSource('boundary', options, urlParameters);
|
|
742
|
-
};
|
|
743
|
-
|
|
744
|
-
// deck.gl
|
|
745
|
-
// SPDX-License-Identifier: MIT
|
|
746
|
-
// Copyright (c) vis.gl contributors
|
|
747
|
-
const boundaryTableSource = async function boundaryTableSource(options) {
|
|
748
|
-
const {
|
|
749
|
-
filters,
|
|
750
|
-
tilesetTableName,
|
|
751
|
-
columns,
|
|
752
|
-
propertiesTableName
|
|
753
|
-
} = options;
|
|
754
|
-
const urlParameters = {
|
|
755
|
-
tilesetTableName,
|
|
756
|
-
propertiesTableName
|
|
757
|
-
};
|
|
758
|
-
if (columns) {
|
|
759
|
-
urlParameters.columns = columns.join(',');
|
|
760
|
-
}
|
|
761
|
-
if (filters) {
|
|
762
|
-
urlParameters.filters = filters;
|
|
763
|
-
}
|
|
764
|
-
return baseSource('boundary', options, urlParameters);
|
|
765
|
-
};
|
|
766
|
-
|
|
767
|
-
/**
|
|
768
|
-
* Return more descriptive error from API
|
|
769
|
-
* @internalRemarks Source: @carto/react-api
|
|
770
|
-
*/
|
|
771
|
-
function dealWithApiError({
|
|
772
|
-
response,
|
|
773
|
-
data
|
|
774
|
-
}) {
|
|
775
|
-
var _data$error, _data$error2;
|
|
776
|
-
if (data.error === 'Column not found') {
|
|
777
|
-
throw new InvalidColumnError(`${data.error} ${data.column_name}`);
|
|
778
|
-
}
|
|
779
|
-
if (typeof data.error === 'string' && (_data$error = data.error) != null && _data$error.includes('Missing columns')) {
|
|
780
|
-
throw new InvalidColumnError(data.error);
|
|
781
|
-
}
|
|
782
|
-
switch (response.status) {
|
|
783
|
-
case 401:
|
|
784
|
-
throw new Error('Unauthorized access. Invalid credentials');
|
|
785
|
-
case 403:
|
|
786
|
-
throw new Error('Forbidden access to the requested data');
|
|
787
|
-
default:
|
|
788
|
-
const msg = data && data.error && typeof data.error === 'string' ? data.error : JSON.stringify((data == null ? void 0 : data.hint) || ((_data$error2 = data.error) == null ? void 0 : _data$error2[0]));
|
|
789
|
-
throw new Error(msg);
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
/** @internalRemarks Source: @carto/react-api */
|
|
793
|
-
async function makeCall({
|
|
794
|
-
url,
|
|
795
|
-
accessToken,
|
|
796
|
-
opts
|
|
797
|
-
}) {
|
|
798
|
-
let response;
|
|
799
|
-
let data;
|
|
800
|
-
const isPost = (opts == null ? void 0 : opts.method) === 'POST';
|
|
801
|
-
try {
|
|
802
|
-
var _opts$abortController;
|
|
803
|
-
response = await fetch(url.toString(), _extends({
|
|
804
|
-
headers: _extends({
|
|
805
|
-
Authorization: `Bearer ${accessToken}`
|
|
806
|
-
}, isPost && {
|
|
807
|
-
'Content-Type': 'application/json'
|
|
808
|
-
})
|
|
809
|
-
}, isPost && {
|
|
810
|
-
method: opts == null ? void 0 : opts.method,
|
|
811
|
-
body: opts == null ? void 0 : opts.body
|
|
812
|
-
}, {
|
|
813
|
-
signal: opts == null || (_opts$abortController = opts.abortController) == null ? void 0 : _opts$abortController.signal
|
|
814
|
-
}, opts == null ? void 0 : opts.otherOptions));
|
|
815
|
-
data = await response.json();
|
|
816
|
-
} catch (error) {
|
|
817
|
-
if (error.name === 'AbortError') throw error;
|
|
818
|
-
throw new Error(`Failed request: ${error}`);
|
|
819
|
-
}
|
|
820
|
-
if (!response.ok) {
|
|
821
|
-
dealWithApiError({
|
|
822
|
-
response,
|
|
823
|
-
data
|
|
824
|
-
});
|
|
825
|
-
}
|
|
826
|
-
return data;
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
/** @internalRemarks Source: @carto/react-api */
|
|
830
|
-
const AVAILABLE_MODELS = ['category', 'histogram', 'formula', 'pick', 'timeseries', 'range', 'scatterplot', 'table'];
|
|
831
|
-
const {
|
|
832
|
-
V3
|
|
833
|
-
} = ApiVersion;
|
|
834
|
-
const REQUEST_GET_MAX_URL_LENGTH = 2048;
|
|
835
|
-
/**
|
|
836
|
-
* Execute a SQL model request.
|
|
837
|
-
* @internalRemarks Source: @carto/react-api
|
|
838
|
-
*/
|
|
839
|
-
function executeModel(props) {
|
|
840
|
-
assert$1(props.source, 'executeModel: missing source');
|
|
841
|
-
assert$1(props.model, 'executeModel: missing model');
|
|
842
|
-
assert$1(props.params, 'executeModel: missing params');
|
|
843
|
-
assert$1(AVAILABLE_MODELS.includes(props.model), `executeModel: model provided isn't valid. Available models: ${AVAILABLE_MODELS.join(', ')}`);
|
|
844
|
-
const {
|
|
845
|
-
model,
|
|
846
|
-
source,
|
|
847
|
-
params,
|
|
848
|
-
opts
|
|
849
|
-
} = props;
|
|
850
|
-
const {
|
|
851
|
-
type,
|
|
852
|
-
apiVersion,
|
|
853
|
-
apiBaseUrl,
|
|
854
|
-
accessToken,
|
|
855
|
-
connectionName,
|
|
856
|
-
clientId
|
|
857
|
-
} = source;
|
|
858
|
-
assert$1(apiBaseUrl, 'executeModel: missing apiBaseUrl');
|
|
859
|
-
assert$1(accessToken, 'executeModel: missing accessToken');
|
|
860
|
-
assert$1(apiVersion === V3, 'executeModel: SQL Model API requires CARTO 3+');
|
|
861
|
-
assert$1(type !== 'tileset', 'executeModel: Tilesets not supported');
|
|
862
|
-
let url = `${apiBaseUrl}/v3/sql/${connectionName}/model/${model}`;
|
|
863
|
-
const {
|
|
864
|
-
data,
|
|
865
|
-
filters,
|
|
866
|
-
filtersLogicalOperator = 'and',
|
|
867
|
-
spatialDataType = 'geo',
|
|
868
|
-
spatialFiltersMode = 'intersects',
|
|
869
|
-
spatialFiltersResolution = 0
|
|
870
|
-
} = source;
|
|
871
|
-
const queryParams = {
|
|
872
|
-
type,
|
|
873
|
-
client: clientId,
|
|
874
|
-
source: data,
|
|
875
|
-
params,
|
|
876
|
-
queryParameters: source.queryParameters || '',
|
|
877
|
-
filters,
|
|
878
|
-
filtersLogicalOperator
|
|
879
|
-
};
|
|
880
|
-
const spatialDataColumn = source.spatialDataColumn || DEFAULT_GEO_COLUMN;
|
|
881
|
-
// Picking Model API requires 'spatialDataColumn'.
|
|
882
|
-
if (model === 'pick') {
|
|
883
|
-
queryParams.spatialDataColumn = spatialDataColumn;
|
|
884
|
-
}
|
|
885
|
-
// API supports multiple filters, we apply it only to spatialDataColumn
|
|
886
|
-
const spatialFilters = source.spatialFilter ? {
|
|
887
|
-
[spatialDataColumn]: source.spatialFilter
|
|
888
|
-
} : undefined;
|
|
889
|
-
if (spatialFilters) {
|
|
890
|
-
queryParams.spatialFilters = spatialFilters;
|
|
891
|
-
queryParams.spatialDataColumn = spatialDataColumn;
|
|
892
|
-
queryParams.spatialDataType = spatialDataType;
|
|
893
|
-
}
|
|
894
|
-
if (spatialDataType !== 'geo') {
|
|
895
|
-
if (spatialFiltersResolution > 0) {
|
|
896
|
-
queryParams.spatialFiltersResolution = spatialFiltersResolution;
|
|
897
|
-
}
|
|
898
|
-
queryParams.spatialFiltersMode = spatialFiltersMode;
|
|
899
|
-
}
|
|
900
|
-
const urlWithSearchParams = url + '?' + objectToURLSearchParams(queryParams).toString();
|
|
901
|
-
const isGet = urlWithSearchParams.length <= REQUEST_GET_MAX_URL_LENGTH;
|
|
902
|
-
if (isGet) {
|
|
903
|
-
url = urlWithSearchParams;
|
|
904
|
-
}
|
|
905
|
-
return makeCall({
|
|
906
|
-
url,
|
|
907
|
-
accessToken: source.accessToken,
|
|
908
|
-
opts: _extends({}, opts, {
|
|
909
|
-
method: isGet ? 'GET' : 'POST'
|
|
910
|
-
}, !isGet && {
|
|
911
|
-
body: JSON.stringify(queryParams)
|
|
912
|
-
})
|
|
913
|
-
});
|
|
914
|
-
}
|
|
915
|
-
function objectToURLSearchParams(object) {
|
|
916
|
-
const params = new URLSearchParams();
|
|
917
|
-
for (const key in object) {
|
|
918
|
-
if (isPureObject(object[key])) {
|
|
919
|
-
params.append(key, JSON.stringify(object[key]));
|
|
920
|
-
} else if (Array.isArray(object[key])) {
|
|
921
|
-
params.append(key, JSON.stringify(object[key]));
|
|
922
|
-
} else if (object[key] === null) {
|
|
923
|
-
params.append(key, 'null');
|
|
924
|
-
} else if (object[key] !== undefined) {
|
|
925
|
-
params.append(key, String(object[key]));
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
return params;
|
|
929
|
-
}
|
|
930
|
-
|
|
931
|
-
const DEFAULT_TILE_SIZE = 512;
|
|
932
|
-
const QUADBIN_ZOOM_MAX_OFFSET = 4;
|
|
933
|
-
function getSpatialFiltersResolution(source, viewState) {
|
|
934
|
-
var _source$dataResolutio, _source$aggregationRe;
|
|
935
|
-
const dataResolution = (_source$dataResolutio = source.dataResolution) != null ? _source$dataResolutio : Number.MAX_VALUE;
|
|
936
|
-
const aggregationResLevel = (_source$aggregationRe = source.aggregationResLevel) != null ? _source$aggregationRe : source.spatialDataType === 'h3' ? DEFAULT_AGGREGATION_RES_LEVEL_H3 : DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN;
|
|
937
|
-
const aggregationResLevelOffset = Math.max(0, Math.floor(aggregationResLevel));
|
|
938
|
-
const currentZoomInt = Math.ceil(viewState.zoom);
|
|
939
|
-
if (source.spatialDataType === 'h3') {
|
|
940
|
-
var _maxH3SpatialFiltersR, _maxH3SpatialFiltersR2;
|
|
941
|
-
const tileSize = DEFAULT_TILE_SIZE;
|
|
942
|
-
const maxResolutionForZoom = (_maxH3SpatialFiltersR = (_maxH3SpatialFiltersR2 = maxH3SpatialFiltersResolutions.find(([zoom]) => zoom === currentZoomInt)) == null ? void 0 : _maxH3SpatialFiltersR2[1]) != null ? _maxH3SpatialFiltersR : Math.max(0, currentZoomInt - 3);
|
|
943
|
-
const maxSpatialFiltersResolution = maxResolutionForZoom ? Math.min(dataResolution, maxResolutionForZoom) : dataResolution;
|
|
944
|
-
const hexagonResolution = getHexagonResolution(viewState, tileSize) + aggregationResLevelOffset;
|
|
945
|
-
return Math.min(hexagonResolution, maxSpatialFiltersResolution);
|
|
946
|
-
}
|
|
947
|
-
if (source.spatialDataType === 'quadbin') {
|
|
948
|
-
const maxResolutionForZoom = currentZoomInt + QUADBIN_ZOOM_MAX_OFFSET;
|
|
949
|
-
const maxSpatialFiltersResolution = Math.min(dataResolution, maxResolutionForZoom);
|
|
950
|
-
const quadsResolution = Math.floor(viewState.zoom) + aggregationResLevelOffset;
|
|
951
|
-
return Math.min(quadsResolution, maxSpatialFiltersResolution);
|
|
952
|
-
}
|
|
953
|
-
return undefined;
|
|
954
|
-
}
|
|
955
|
-
const maxH3SpatialFiltersResolutions = [[20, 14], [19, 13], [18, 12], [17, 11], [16, 10], [15, 9], [14, 8], [13, 7], [12, 7], [11, 7], [10, 6], [9, 6], [8, 5], [7, 4], [6, 4], [5, 3], [4, 2], [3, 1], [2, 1], [1, 0]];
|
|
956
|
-
// stolen from https://github.com/visgl/deck.gl/blob/master/modules/carto/src/layers/h3-tileset-2d.ts
|
|
957
|
-
// Relative scale factor (0 = no biasing, 2 = a few hexagons cover view)
|
|
958
|
-
const BIAS = 2;
|
|
959
|
-
// Resolution conversion function. Takes a WebMercatorViewport and returns
|
|
960
|
-
// a H3 resolution such that the screen space size of the hexagons is
|
|
961
|
-
// similar
|
|
962
|
-
function getHexagonResolution(viewport, tileSize) {
|
|
963
|
-
// Difference in given tile size compared to deck's internal 512px tile size,
|
|
964
|
-
// expressed as an offset to the viewport zoom.
|
|
965
|
-
const zoomOffset = Math.log2(tileSize / DEFAULT_TILE_SIZE);
|
|
966
|
-
const hexagonScaleFactor = 2 / 3 * (viewport.zoom - zoomOffset);
|
|
967
|
-
const latitudeScaleFactor = Math.log(1 / Math.cos(Math.PI * viewport.latitude / 180));
|
|
968
|
-
// Clip and bias
|
|
969
|
-
return Math.max(0, Math.floor(hexagonScaleFactor + latitudeScaleFactor - BIAS));
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
/**
|
|
973
|
-
* Source for Widget API requests on a data source defined by a SQL query.
|
|
974
|
-
*
|
|
975
|
-
* Abstract class. Use {@link WidgetQuerySource} or {@link WidgetTableSource}.
|
|
976
|
-
*/
|
|
977
|
-
class WidgetSource {
|
|
978
|
-
constructor(props) {
|
|
979
|
-
this.props = void 0;
|
|
980
|
-
this.props = _extends({}, WidgetSource.defaultProps, props);
|
|
981
|
-
}
|
|
982
|
-
_getModelSource(owner) {
|
|
983
|
-
const props = this.props;
|
|
984
|
-
return {
|
|
985
|
-
apiVersion: props.apiVersion,
|
|
986
|
-
apiBaseUrl: props.apiBaseUrl,
|
|
987
|
-
clientId: props.clientId,
|
|
988
|
-
accessToken: props.accessToken,
|
|
989
|
-
connectionName: props.connectionName,
|
|
990
|
-
filters: getApplicableFilters(owner, props.filters),
|
|
991
|
-
filtersLogicalOperator: props.filtersLogicalOperator,
|
|
992
|
-
spatialDataType: props.spatialDataType,
|
|
993
|
-
spatialDataColumn: props.spatialDataColumn,
|
|
994
|
-
dataResolution: props.dataResolution
|
|
995
|
-
};
|
|
996
|
-
}
|
|
997
|
-
_getSpatialFiltersResolution(source, spatialFilter, referenceViewState) {
|
|
998
|
-
// spatialFiltersResolution applies only to spatial index sources.
|
|
999
|
-
if (!spatialFilter || source.spatialDataType === 'geo') {
|
|
1000
|
-
return;
|
|
1001
|
-
}
|
|
1002
|
-
if (!referenceViewState) {
|
|
1003
|
-
throw new Error('Missing required option, "spatialIndexReferenceViewState".');
|
|
1004
|
-
}
|
|
1005
|
-
return getSpatialFiltersResolution(source, referenceViewState);
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
WidgetSource.defaultProps = {
|
|
1009
|
-
apiVersion: ApiVersion.V3,
|
|
1010
|
-
apiBaseUrl: DEFAULT_API_BASE_URL,
|
|
1011
|
-
clientId: getClient(),
|
|
1012
|
-
filters: {},
|
|
1013
|
-
filtersLogicalOperator: 'and'
|
|
1014
|
-
};
|
|
1015
|
-
|
|
1016
|
-
const _excluded$1 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
|
|
1017
|
-
_excluded2 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
|
|
1018
|
-
_excluded3 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController", "operationExp"],
|
|
1019
|
-
_excluded4 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
|
|
1020
|
-
_excluded5 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
|
|
1021
|
-
_excluded6 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
|
|
1022
|
-
_excluded7 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
|
|
1023
|
-
_excluded8 = ["filterOwner", "abortController", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState"];
|
|
1024
|
-
/**
|
|
1025
|
-
* Source for Widget API requests.
|
|
1026
|
-
*
|
|
1027
|
-
* Abstract class. Use {@link WidgetQuerySource} or {@link WidgetTableSource}.
|
|
1028
|
-
*/
|
|
1029
|
-
class WidgetRemoteSource extends WidgetSource {
|
|
1030
|
-
async getCategories(options) {
|
|
1031
|
-
const {
|
|
1032
|
-
filterOwner,
|
|
1033
|
-
spatialFilter,
|
|
1034
|
-
spatialFiltersMode,
|
|
1035
|
-
spatialIndexReferenceViewState,
|
|
1036
|
-
abortController
|
|
1037
|
-
} = options,
|
|
1038
|
-
params = _objectWithoutPropertiesLoose(options, _excluded$1);
|
|
1039
|
-
const {
|
|
1040
|
-
column,
|
|
1041
|
-
operation,
|
|
1042
|
-
operationColumn
|
|
1043
|
-
} = params;
|
|
1044
|
-
const source = this.getModelSource(filterOwner);
|
|
1045
|
-
const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
1046
|
-
return executeModel({
|
|
1047
|
-
model: 'category',
|
|
1048
|
-
source: _extends({}, source, {
|
|
1049
|
-
spatialFiltersResolution,
|
|
1050
|
-
spatialFiltersMode,
|
|
1051
|
-
spatialFilter
|
|
1052
|
-
}),
|
|
1053
|
-
params: {
|
|
1054
|
-
column,
|
|
1055
|
-
operation,
|
|
1056
|
-
operationColumn: operationColumn || column
|
|
1057
|
-
},
|
|
1058
|
-
opts: {
|
|
1059
|
-
abortController
|
|
1060
|
-
}
|
|
1061
|
-
}).then(res => normalizeObjectKeys(res.rows));
|
|
1062
|
-
}
|
|
1063
|
-
async getFeatures(options) {
|
|
1064
|
-
const {
|
|
1065
|
-
filterOwner,
|
|
1066
|
-
spatialFilter,
|
|
1067
|
-
spatialFiltersMode,
|
|
1068
|
-
spatialIndexReferenceViewState,
|
|
1069
|
-
abortController
|
|
1070
|
-
} = options,
|
|
1071
|
-
params = _objectWithoutPropertiesLoose(options, _excluded2);
|
|
1072
|
-
const {
|
|
1073
|
-
columns,
|
|
1074
|
-
dataType,
|
|
1075
|
-
featureIds,
|
|
1076
|
-
z,
|
|
1077
|
-
limit,
|
|
1078
|
-
tileResolution
|
|
1079
|
-
} = params;
|
|
1080
|
-
const source = this.getModelSource(filterOwner);
|
|
1081
|
-
const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
1082
|
-
return executeModel({
|
|
1083
|
-
model: 'pick',
|
|
1084
|
-
source: _extends({}, source, {
|
|
1085
|
-
spatialFiltersResolution,
|
|
1086
|
-
spatialFiltersMode,
|
|
1087
|
-
spatialFilter
|
|
1088
|
-
}),
|
|
1089
|
-
params: {
|
|
1090
|
-
columns,
|
|
1091
|
-
dataType,
|
|
1092
|
-
featureIds,
|
|
1093
|
-
z,
|
|
1094
|
-
limit: limit || 1000,
|
|
1095
|
-
tileResolution: tileResolution || DEFAULT_TILE_RESOLUTION
|
|
1096
|
-
},
|
|
1097
|
-
opts: {
|
|
1098
|
-
abortController
|
|
1099
|
-
}
|
|
1100
|
-
// Avoid `normalizeObjectKeys()`, which changes column names.
|
|
1101
|
-
}).then(({
|
|
1102
|
-
rows
|
|
1103
|
-
}) => ({
|
|
1104
|
-
rows
|
|
1105
|
-
}));
|
|
1106
|
-
}
|
|
1107
|
-
async getFormula(options) {
|
|
1108
|
-
const {
|
|
1109
|
-
filterOwner,
|
|
1110
|
-
spatialFilter,
|
|
1111
|
-
spatialFiltersMode,
|
|
1112
|
-
spatialIndexReferenceViewState,
|
|
1113
|
-
abortController,
|
|
1114
|
-
operationExp
|
|
1115
|
-
} = options,
|
|
1116
|
-
params = _objectWithoutPropertiesLoose(options, _excluded3);
|
|
1117
|
-
const {
|
|
1118
|
-
column,
|
|
1119
|
-
operation
|
|
1120
|
-
} = params;
|
|
1121
|
-
const source = this.getModelSource(filterOwner);
|
|
1122
|
-
const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
1123
|
-
return executeModel({
|
|
1124
|
-
model: 'formula',
|
|
1125
|
-
source: _extends({}, source, {
|
|
1126
|
-
spatialFiltersResolution,
|
|
1127
|
-
spatialFiltersMode,
|
|
1128
|
-
spatialFilter
|
|
1129
|
-
}),
|
|
1130
|
-
params: {
|
|
1131
|
-
column: column != null ? column : '*',
|
|
1132
|
-
operation: operation != null ? operation : 'count',
|
|
1133
|
-
operationExp
|
|
1134
|
-
},
|
|
1135
|
-
opts: {
|
|
1136
|
-
abortController
|
|
1137
|
-
}
|
|
1138
|
-
}).then(res => normalizeObjectKeys(res.rows[0]));
|
|
1139
|
-
}
|
|
1140
|
-
async getHistogram(options) {
|
|
1141
|
-
const {
|
|
1142
|
-
filterOwner,
|
|
1143
|
-
spatialFilter,
|
|
1144
|
-
spatialFiltersMode,
|
|
1145
|
-
spatialIndexReferenceViewState,
|
|
1146
|
-
abortController
|
|
1147
|
-
} = options,
|
|
1148
|
-
params = _objectWithoutPropertiesLoose(options, _excluded4);
|
|
1149
|
-
const {
|
|
1150
|
-
column,
|
|
1151
|
-
operation,
|
|
1152
|
-
ticks
|
|
1153
|
-
} = params;
|
|
1154
|
-
const source = this.getModelSource(filterOwner);
|
|
1155
|
-
const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
1156
|
-
const data = await executeModel({
|
|
1157
|
-
model: 'histogram',
|
|
1158
|
-
source: _extends({}, source, {
|
|
1159
|
-
spatialFiltersResolution,
|
|
1160
|
-
spatialFiltersMode,
|
|
1161
|
-
spatialFilter
|
|
1162
|
-
}),
|
|
1163
|
-
params: {
|
|
1164
|
-
column,
|
|
1165
|
-
operation,
|
|
1166
|
-
ticks
|
|
1167
|
-
},
|
|
1168
|
-
opts: {
|
|
1169
|
-
abortController
|
|
1170
|
-
}
|
|
1171
|
-
}).then(res => normalizeObjectKeys(res.rows));
|
|
1172
|
-
if (data.length) {
|
|
1173
|
-
// Given N ticks the API returns up to N+1 bins, omitting any empty bins. Bins
|
|
1174
|
-
// include 1 bin below the lowest tick, N-1 between ticks, and 1 bin above the highest tick.
|
|
1175
|
-
const result = Array(ticks.length + 1).fill(0);
|
|
1176
|
-
data.forEach(({
|
|
1177
|
-
tick,
|
|
1178
|
-
value
|
|
1179
|
-
}) => result[tick] = value);
|
|
1180
|
-
return result;
|
|
1181
|
-
}
|
|
1182
|
-
return [];
|
|
1183
|
-
}
|
|
1184
|
-
async getRange(options) {
|
|
1185
|
-
const {
|
|
1186
|
-
filterOwner,
|
|
1187
|
-
spatialFilter,
|
|
1188
|
-
spatialFiltersMode,
|
|
1189
|
-
spatialIndexReferenceViewState,
|
|
1190
|
-
abortController
|
|
1191
|
-
} = options,
|
|
1192
|
-
params = _objectWithoutPropertiesLoose(options, _excluded5);
|
|
1193
|
-
const {
|
|
1194
|
-
column
|
|
1195
|
-
} = params;
|
|
1196
|
-
const source = this.getModelSource(filterOwner);
|
|
1197
|
-
const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
1198
|
-
return executeModel({
|
|
1199
|
-
model: 'range',
|
|
1200
|
-
source: _extends({}, source, {
|
|
1201
|
-
spatialFiltersResolution,
|
|
1202
|
-
spatialFiltersMode,
|
|
1203
|
-
spatialFilter
|
|
1204
|
-
}),
|
|
1205
|
-
params: {
|
|
1206
|
-
column
|
|
1207
|
-
},
|
|
1208
|
-
opts: {
|
|
1209
|
-
abortController
|
|
1210
|
-
}
|
|
1211
|
-
}).then(res => normalizeObjectKeys(res.rows[0]));
|
|
1212
|
-
}
|
|
1213
|
-
async getScatter(options) {
|
|
1214
|
-
const {
|
|
1215
|
-
filterOwner,
|
|
1216
|
-
spatialFilter,
|
|
1217
|
-
spatialFiltersMode,
|
|
1218
|
-
spatialIndexReferenceViewState,
|
|
1219
|
-
abortController
|
|
1220
|
-
} = options,
|
|
1221
|
-
params = _objectWithoutPropertiesLoose(options, _excluded6);
|
|
1222
|
-
const {
|
|
1223
|
-
xAxisColumn,
|
|
1224
|
-
xAxisJoinOperation,
|
|
1225
|
-
yAxisColumn,
|
|
1226
|
-
yAxisJoinOperation
|
|
1227
|
-
} = params;
|
|
1228
|
-
const source = this.getModelSource(filterOwner);
|
|
1229
|
-
const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
1230
|
-
// Make sure this is sync with the same constant in cloud-native/maps-api
|
|
1231
|
-
const HARD_LIMIT = 500;
|
|
1232
|
-
return executeModel({
|
|
1233
|
-
model: 'scatterplot',
|
|
1234
|
-
source: _extends({}, source, {
|
|
1235
|
-
spatialFiltersResolution,
|
|
1236
|
-
spatialFiltersMode,
|
|
1237
|
-
spatialFilter
|
|
1238
|
-
}),
|
|
1239
|
-
params: {
|
|
1240
|
-
xAxisColumn,
|
|
1241
|
-
xAxisJoinOperation,
|
|
1242
|
-
yAxisColumn,
|
|
1243
|
-
yAxisJoinOperation,
|
|
1244
|
-
limit: HARD_LIMIT
|
|
1245
|
-
},
|
|
1246
|
-
opts: {
|
|
1247
|
-
abortController
|
|
1248
|
-
}
|
|
1249
|
-
}).then(res => normalizeObjectKeys(res.rows)).then(res => res.map(({
|
|
1250
|
-
x,
|
|
1251
|
-
y
|
|
1252
|
-
}) => [x, y]));
|
|
1253
|
-
}
|
|
1254
|
-
async getTable(options) {
|
|
1255
|
-
const {
|
|
1256
|
-
filterOwner,
|
|
1257
|
-
spatialFilter,
|
|
1258
|
-
spatialFiltersMode,
|
|
1259
|
-
spatialIndexReferenceViewState,
|
|
1260
|
-
abortController
|
|
1261
|
-
} = options,
|
|
1262
|
-
params = _objectWithoutPropertiesLoose(options, _excluded7);
|
|
1263
|
-
const {
|
|
1264
|
-
columns,
|
|
1265
|
-
sortBy,
|
|
1266
|
-
sortDirection,
|
|
1267
|
-
offset = 0,
|
|
1268
|
-
limit = 10
|
|
1269
|
-
} = params;
|
|
1270
|
-
const source = this.getModelSource(filterOwner);
|
|
1271
|
-
const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
1272
|
-
return executeModel({
|
|
1273
|
-
model: 'table',
|
|
1274
|
-
source: _extends({}, source, {
|
|
1275
|
-
spatialFiltersResolution,
|
|
1276
|
-
spatialFiltersMode,
|
|
1277
|
-
spatialFilter
|
|
1278
|
-
}),
|
|
1279
|
-
params: {
|
|
1280
|
-
column: columns,
|
|
1281
|
-
sortBy,
|
|
1282
|
-
sortDirection,
|
|
1283
|
-
limit,
|
|
1284
|
-
offset
|
|
1285
|
-
},
|
|
1286
|
-
opts: {
|
|
1287
|
-
abortController
|
|
1288
|
-
}
|
|
1289
|
-
}).then(res => {
|
|
1290
|
-
var _res$rows, _res$metadata$total, _res$metadata, _res$METADATA;
|
|
1291
|
-
return {
|
|
1292
|
-
// Avoid `normalizeObjectKeys()`, which changes column names.
|
|
1293
|
-
rows: (_res$rows = res.rows) != null ? _res$rows : res.ROWS,
|
|
1294
|
-
totalCount: (_res$metadata$total = (_res$metadata = res.metadata) == null ? void 0 : _res$metadata.total) != null ? _res$metadata$total : (_res$METADATA = res.METADATA) == null ? void 0 : _res$METADATA.TOTAL
|
|
1295
|
-
};
|
|
1296
|
-
});
|
|
1297
|
-
}
|
|
1298
|
-
async getTimeSeries(options) {
|
|
1299
|
-
const {
|
|
1300
|
-
filterOwner,
|
|
1301
|
-
abortController,
|
|
1302
|
-
spatialFilter,
|
|
1303
|
-
spatialFiltersMode,
|
|
1304
|
-
spatialIndexReferenceViewState
|
|
1305
|
-
} = options,
|
|
1306
|
-
params = _objectWithoutPropertiesLoose(options, _excluded8);
|
|
1307
|
-
const {
|
|
1308
|
-
column,
|
|
1309
|
-
operationColumn,
|
|
1310
|
-
joinOperation,
|
|
1311
|
-
operation,
|
|
1312
|
-
stepSize,
|
|
1313
|
-
stepMultiplier,
|
|
1314
|
-
splitByCategory,
|
|
1315
|
-
splitByCategoryLimit,
|
|
1316
|
-
splitByCategoryValues
|
|
1317
|
-
} = params;
|
|
1318
|
-
const source = this.getModelSource(filterOwner);
|
|
1319
|
-
const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
1320
|
-
return executeModel({
|
|
1321
|
-
model: 'timeseries',
|
|
1322
|
-
source: _extends({}, source, {
|
|
1323
|
-
spatialFiltersResolution,
|
|
1324
|
-
spatialFiltersMode,
|
|
1325
|
-
spatialFilter
|
|
1326
|
-
}),
|
|
1327
|
-
params: {
|
|
1328
|
-
column,
|
|
1329
|
-
stepSize,
|
|
1330
|
-
stepMultiplier,
|
|
1331
|
-
operationColumn: operationColumn || column,
|
|
1332
|
-
joinOperation,
|
|
1333
|
-
operation,
|
|
1334
|
-
splitByCategory,
|
|
1335
|
-
splitByCategoryLimit,
|
|
1336
|
-
splitByCategoryValues
|
|
1337
|
-
},
|
|
1338
|
-
opts: {
|
|
1339
|
-
abortController
|
|
1340
|
-
}
|
|
1341
|
-
}).then(res => {
|
|
1342
|
-
var _res$metadata2;
|
|
1343
|
-
return {
|
|
1344
|
-
rows: normalizeObjectKeys(res.rows),
|
|
1345
|
-
categories: (_res$metadata2 = res.metadata) == null ? void 0 : _res$metadata2.categories
|
|
1346
|
-
};
|
|
1347
|
-
});
|
|
1348
|
-
}
|
|
1349
|
-
}
|
|
1350
|
-
|
|
1351
|
-
/**
|
|
1352
|
-
* Source for Widget API requests on a data source defined by a SQL query.
|
|
1353
|
-
*
|
|
1354
|
-
* Generally not intended to be constructed directly. Instead, call
|
|
1355
|
-
* {@link vectorQuerySource}, {@link h3QuerySource}, or {@link quadbinQuerySource},
|
|
1356
|
-
* which can be shared with map layers. Sources contain a `widgetSource` property,
|
|
1357
|
-
* for use by widget implementations.
|
|
1358
|
-
*
|
|
1359
|
-
* Example:
|
|
1360
|
-
*
|
|
1361
|
-
* ```javascript
|
|
1362
|
-
* import { vectorQuerySource } from '@carto/api-client';
|
|
1363
|
-
*
|
|
1364
|
-
* const data = vectorQuerySource({
|
|
1365
|
-
* accessToken: '••••',
|
|
1366
|
-
* connectionName: 'carto_dw',
|
|
1367
|
-
* sqlQuery: 'SELECT * FROM carto-demo-data.demo_tables.retail_stores'
|
|
1368
|
-
* });
|
|
1369
|
-
*
|
|
1370
|
-
* const { widgetSource } = await data;
|
|
1371
|
-
* ```
|
|
1372
|
-
*/
|
|
1373
|
-
class WidgetQuerySource extends WidgetRemoteSource {
|
|
1374
|
-
getModelSource(owner) {
|
|
1375
|
-
return _extends({}, super._getModelSource(owner), {
|
|
1376
|
-
type: 'query',
|
|
1377
|
-
data: this.props.sqlQuery,
|
|
1378
|
-
queryParameters: this.props.queryParameters
|
|
1379
|
-
});
|
|
1380
|
-
}
|
|
1381
|
-
}
|
|
1382
|
-
|
|
1383
|
-
/**
|
|
1384
|
-
* Source for Widget API requests on a data source defined as a table.
|
|
1385
|
-
*
|
|
1386
|
-
* Generally not intended to be constructed directly. Instead, call
|
|
1387
|
-
* {@link vectorTableSource}, {@link h3TableSource}, or {@link quadbinTableSource},
|
|
1388
|
-
* which can be shared with map layers. Sources contain a `widgetSource` property,
|
|
1389
|
-
* for use by widget implementations.
|
|
1390
|
-
*
|
|
1391
|
-
* Example:
|
|
1392
|
-
*
|
|
1393
|
-
* ```javascript
|
|
1394
|
-
* import { vectorTableSource } from '@carto/api-client';
|
|
1395
|
-
*
|
|
1396
|
-
* const data = vectorTableSource({
|
|
1397
|
-
* accessToken: '••••',
|
|
1398
|
-
* connectionName: 'carto_dw',
|
|
1399
|
-
* tableName: 'carto-demo-data.demo_tables.retail_stores'
|
|
1400
|
-
* });
|
|
1401
|
-
*
|
|
1402
|
-
* const { widgetSource } = await data;
|
|
1403
|
-
* ```
|
|
1404
|
-
*/
|
|
1405
|
-
class WidgetTableSource extends WidgetRemoteSource {
|
|
1406
|
-
getModelSource(owner) {
|
|
1407
|
-
return _extends({}, super._getModelSource(owner), {
|
|
1408
|
-
type: 'table',
|
|
1409
|
-
data: this.props.tableName
|
|
1410
|
-
});
|
|
1411
|
-
}
|
|
1412
|
-
}
|
|
1413
|
-
|
|
1414
|
-
function makeIntervalComplete(intervals) {
|
|
1415
|
-
return intervals.map(val => {
|
|
1416
|
-
if (val[0] === undefined || val[0] === null) {
|
|
1417
|
-
return [Number.MIN_SAFE_INTEGER, val[1]];
|
|
1418
|
-
}
|
|
1419
|
-
if (val[1] === undefined || val[1] === null) {
|
|
1420
|
-
return [val[0], Number.MAX_SAFE_INTEGER];
|
|
1421
|
-
}
|
|
1422
|
-
return val;
|
|
1423
|
-
});
|
|
1424
|
-
}
|
|
1425
|
-
|
|
1426
|
-
const filterFunctions = {
|
|
1427
|
-
[FilterType.IN]: filterIn,
|
|
1428
|
-
[FilterType.BETWEEN]: filterBetween,
|
|
1429
|
-
[FilterType.TIME]: filterTime,
|
|
1430
|
-
[FilterType.CLOSED_OPEN]: filterClosedOpen,
|
|
1431
|
-
[FilterType.STRING_SEARCH]: filterStringSearch
|
|
1432
|
-
};
|
|
1433
|
-
function filterIn(filterValues, featureValue) {
|
|
1434
|
-
return filterValues.includes(featureValue);
|
|
1435
|
-
}
|
|
1436
|
-
// FilterTypes.BETWEEN
|
|
1437
|
-
function filterBetween(filterValues, featureValue) {
|
|
1438
|
-
const checkRange = range => {
|
|
1439
|
-
const [lowerBound, upperBound] = range;
|
|
1440
|
-
return featureValue >= lowerBound && featureValue <= upperBound;
|
|
1441
|
-
};
|
|
1442
|
-
return makeIntervalComplete(filterValues).some(checkRange);
|
|
1443
|
-
}
|
|
1444
|
-
function filterTime(filterValues, featureValue) {
|
|
1445
|
-
const featureValueAsTimestamp = new Date(featureValue).getTime();
|
|
1446
|
-
if (isFinite(featureValueAsTimestamp)) {
|
|
1447
|
-
return filterBetween(filterValues, featureValueAsTimestamp);
|
|
1448
|
-
} else {
|
|
1449
|
-
throw new Error(`Column used to filter by time isn't well formatted.`);
|
|
1450
|
-
}
|
|
1451
|
-
}
|
|
1452
|
-
// FilterTypes.CLOSED_OPEN
|
|
1453
|
-
function filterClosedOpen(filterValues, featureValue) {
|
|
1454
|
-
const checkRange = range => {
|
|
1455
|
-
const [lowerBound, upperBound] = range;
|
|
1456
|
-
return featureValue >= lowerBound && featureValue < upperBound;
|
|
1457
|
-
};
|
|
1458
|
-
return makeIntervalComplete(filterValues).some(checkRange);
|
|
1459
|
-
}
|
|
1460
|
-
// FilterTypes.STRING_SEARCH
|
|
1461
|
-
function filterStringSearch(filterValues, featureValue, params = {}) {
|
|
1462
|
-
const normalizedFeatureValue = normalize(featureValue, params);
|
|
1463
|
-
const stringRegExp = params.useRegExp ? filterValues : filterValues.map(filterValue => {
|
|
1464
|
-
let stringRegExp = escapeRegExp(normalize(filterValue, params));
|
|
1465
|
-
if (params.mustStart) stringRegExp = `^${stringRegExp}`;
|
|
1466
|
-
if (params.mustEnd) stringRegExp = `${stringRegExp}$`;
|
|
1467
|
-
return stringRegExp;
|
|
1468
|
-
});
|
|
1469
|
-
const regex = new RegExp(stringRegExp.join('|'), params.caseSensitive ? 'g' : 'gi');
|
|
1470
|
-
return !!normalizedFeatureValue.match(regex);
|
|
1471
|
-
}
|
|
1472
|
-
// Aux
|
|
1473
|
-
const specialCharRegExp = /[.*+?^${}()|[\]\\]/g;
|
|
1474
|
-
const normalizeRegExp = /(?:[\^`\xA8\xAF\xB4\xB7\xB8\u02B0-\u034E\u0350-\u0357\u035D-\u0362\u0374\u0375\u037A\u0384\u0385\u0483-\u0487\u0559\u0591-\u05A1\u05A3-\u05BD\u05BF\u05C1\u05C2\u05C4\u064B-\u0652\u0657\u0658\u06DF\u06E0\u06E5\u06E6\u06EA-\u06EC\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F5\u0818\u0819\u0898-\u089F\u08C9-\u08D2\u08E3-\u08FE\u093C\u094D\u0951-\u0954\u0971\u09BC\u09CD\u0A3C\u0A4D\u0ABC\u0ACD\u0AFD-\u0AFF\u0B3C\u0B4D\u0B55\u0BCD\u0C3C\u0C4D\u0CBC\u0CCD\u0D3B\u0D3C\u0D4D\u0DCA\u0E3A\u0E47-\u0E4C\u0E4E\u0EBA\u0EC8-\u0ECC\u0F18\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F82-\u0F84\u0F86\u0F87\u0FC6\u1037\u1039\u103A\u1063\u1064\u1069-\u106D\u1087-\u108D\u108F\u109A\u109B\u135D-\u135F\u1714\u1715\u1734\u17C9-\u17D3\u17DD\u1939-\u193B\u1A60\u1A75-\u1A7C\u1A7F\u1AB0-\u1ABE\u1AC1-\u1ACB\u1B34\u1B44\u1B6B-\u1B73\u1BAA\u1BAB\u1BE6\u1BF2\u1BF3\u1C36\u1C37\u1C78-\u1C7D\u1CD0-\u1CE8\u1CED\u1CF4\u1CF7-\u1CF9\u1D2C-\u1D6A\u1DC4-\u1DCF\u1DF5-\u1DFF\u1FBD\u1FBF-\u1FC1\u1FCD-\u1FCF\u1FDD-\u1FDF\u1FED-\u1FEF\u1FFD\u1FFE\u2CEF-\u2CF1\u2E2F\u302A-\u302F\u3099-\u309C\u30FC\uA66F\uA67C\uA67D\uA67F\uA69C\uA69D\uA6F0\uA6F1\uA700-\uA721\uA788-\uA78A\uA7F8\uA7F9\uA806\uA82C\uA8C4\uA8E0-\uA8F1\uA92B-\uA92E\uA953\uA9B3\uA9C0\uA9E5\uAA7B-\uAA7D\uAABF-\uAAC2\uAAF6\uAB5B-\uAB5F\uAB69-\uAB6B\uABEC\uABED\uFB1E\uFE20-\uFE2F\uFF3E\uFF40\uFF70\uFF9E\uFF9F\uFFE3]|\uD800\uDEE0|\uD801[\uDF80-\uDF85\uDF87-\uDFB0\uDFB2-\uDFBA]|\uD802[\uDE38-\uDE3A\uDE3F\uDEE5\uDEE6]|\uD803[\uDD22-\uDD27\uDD4E\uDD69-\uDD6D\uDEFD-\uDEFF\uDF46-\uDF50\uDF82-\uDF85]|\uD804[\uDC46\uDC70\uDCB9\uDCBA\uDD33\uDD34\uDD73\uDDC0\uDDCA-\uDDCC\uDE35\uDE36\uDEE9\uDEEA\uDF3B\uDF3C\uDF4D\uDF66-\uDF6C\uDF70-\uDF74\uDFCE-\uDFD0\uDFD2\uDFD3\uDFE1\uDFE2]|\uD805[\uDC42\uDC46\uDCC2\uDCC3\uDDBF\uDDC0\uDE3F\uDEB6\uDEB7\uDF2B]|\uD806[\uDC39\uDC3A\uDD3D\uDD3E\uDD43\uDDE0\uDE34\uDE47\uDE99]|\uD807[\uDC3F\uDD42\uDD44\uDD45\uDD97\uDF41\uDF42\uDF5A]|\uD80D[\uDC47-\uDC55]|\uD818\uDD2F|\uD81A[\uDEF0-\uDEF4\uDF30-\uDF36]|\uD81B[\uDD6B\uDD6C\uDF8F-\uDF9F\uDFF0\uDFF1]|\uD82B[\uDFF0-\uDFF3\uDFF5-\uDFFB\uDFFD\uDFFE]|\uD833[\uDF00-\uDF2D\uDF30-\uDF46]|\uD834[\uDD67-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD]|\uD838[\uDC30-\uDC6D\uDD30-\uDD36\uDEAE\uDEEC-\uDEEF]|\uD839[\uDDEE\uDDEF]|\uD83A[\uDCD0-\uDCD6\uDD44-\uDD46\uDD48-\uDD4A])/g;
|
|
1475
|
-
function escapeRegExp(value) {
|
|
1476
|
-
return value.replace(specialCharRegExp, '\\$&');
|
|
1477
|
-
}
|
|
1478
|
-
function normalize(data, params) {
|
|
1479
|
-
let normalizedData = String(data);
|
|
1480
|
-
if (!params.keepSpecialCharacters) normalizedData = normalizedData.normalize('NFD').replace(normalizeRegExp, '');
|
|
1481
|
-
return normalizedData;
|
|
1482
|
-
}
|
|
1483
|
-
|
|
1484
|
-
const LOGICAL_OPERATOR_METHODS = {
|
|
1485
|
-
and: 'every',
|
|
1486
|
-
or: 'some'
|
|
1487
|
-
};
|
|
1488
|
-
function passesFilter(columns, filters, feature, filtersLogicalOperator) {
|
|
1489
|
-
const method = LOGICAL_OPERATOR_METHODS[filtersLogicalOperator];
|
|
1490
|
-
return columns[method](column => {
|
|
1491
|
-
const columnFilters = filters[column];
|
|
1492
|
-
const columnFilterTypes = Object.keys(columnFilters);
|
|
1493
|
-
if (!feature || feature[column] === null || feature[column] === undefined) {
|
|
1494
|
-
return false;
|
|
1495
|
-
}
|
|
1496
|
-
return columnFilterTypes.every(filter => {
|
|
1497
|
-
const filterFunction = filterFunctions[filter];
|
|
1498
|
-
if (!filterFunction) {
|
|
1499
|
-
throw new Error(`"${filter}" filter is not implemented.`);
|
|
1500
|
-
}
|
|
1501
|
-
return filterFunction(columnFilters[filter].values, feature[column], columnFilters[filter].params);
|
|
1502
|
-
});
|
|
1503
|
-
});
|
|
1504
|
-
}
|
|
1505
|
-
function buildFeatureFilter({
|
|
1506
|
-
filters = {},
|
|
1507
|
-
type = 'boolean',
|
|
1508
|
-
filtersLogicalOperator = 'and'
|
|
1509
|
-
}) {
|
|
1510
|
-
const columns = Object.keys(filters);
|
|
1511
|
-
if (!columns.length) {
|
|
1512
|
-
return () => type === 'number' ? 1 : true;
|
|
1513
|
-
}
|
|
1514
|
-
return feature => {
|
|
1515
|
-
const f = feature.properties || feature;
|
|
1516
|
-
const featurePassesFilter = passesFilter(columns, filters, f, filtersLogicalOperator);
|
|
1517
|
-
return type === 'number' ? Number(featurePassesFilter) : featurePassesFilter;
|
|
1518
|
-
};
|
|
1519
|
-
}
|
|
1520
|
-
// Apply certain filters to a collection of features
|
|
1521
|
-
function applyFilters(features, filters, filtersLogicalOperator) {
|
|
1522
|
-
return Object.keys(filters).length ? features.filter(buildFeatureFilter({
|
|
1523
|
-
filters,
|
|
1524
|
-
filtersLogicalOperator
|
|
1525
|
-
})) : features;
|
|
1526
|
-
}
|
|
1527
|
-
// Binary
|
|
1528
|
-
function buildBinaryFeatureFilter({
|
|
1529
|
-
filters = {}
|
|
1530
|
-
}) {
|
|
1531
|
-
const columns = Object.keys(filters);
|
|
1532
|
-
if (!columns.length) {
|
|
1533
|
-
return () => 1;
|
|
1534
|
-
}
|
|
1535
|
-
return (featureIdIdx, binaryData) => passesFilterUsingBinary(columns, filters, featureIdIdx, binaryData);
|
|
1536
|
-
}
|
|
1537
|
-
function getValueFromNumericProps(featureIdIdx, binaryData, {
|
|
1538
|
-
column
|
|
1539
|
-
}) {
|
|
1540
|
-
var _binaryData$numericPr;
|
|
1541
|
-
return (_binaryData$numericPr = binaryData.numericProps) == null || (_binaryData$numericPr = _binaryData$numericPr[column]) == null ? void 0 : _binaryData$numericPr.value[featureIdIdx];
|
|
1542
|
-
}
|
|
1543
|
-
function getValueFromProperties(featureIdIdx, binaryData, {
|
|
1544
|
-
column
|
|
1545
|
-
}) {
|
|
1546
|
-
var _binaryData$propertie;
|
|
1547
|
-
const propertyIdx = binaryData.featureIds.value[featureIdIdx];
|
|
1548
|
-
return (_binaryData$propertie = binaryData.properties[propertyIdx]) == null ? void 0 : _binaryData$propertie[column];
|
|
1549
|
-
}
|
|
1550
|
-
const GET_VALUE_BY_BINARY_PROP = {
|
|
1551
|
-
properties: getValueFromProperties,
|
|
1552
|
-
numericProps: getValueFromNumericProps
|
|
1553
|
-
};
|
|
1554
|
-
function getBinaryPropertyByFilterValues(filterValues) {
|
|
1555
|
-
return typeof filterValues.flat()[0] === 'string' ? 'properties' : 'numericProps';
|
|
1556
|
-
}
|
|
1557
|
-
function getFeatureValue(featureIdIdx, binaryData, filter) {
|
|
1558
|
-
const {
|
|
1559
|
-
column,
|
|
1560
|
-
values
|
|
1561
|
-
} = filter;
|
|
1562
|
-
const binaryProp = getBinaryPropertyByFilterValues(values);
|
|
1563
|
-
const getFeatureValueFn = GET_VALUE_BY_BINARY_PROP[binaryProp];
|
|
1564
|
-
return getFeatureValueFn(featureIdIdx, binaryData, {
|
|
1565
|
-
column
|
|
1566
|
-
});
|
|
1567
|
-
}
|
|
1568
|
-
function passesFilterUsingBinary(columns, filters, featureIdIdx, binaryData) {
|
|
1569
|
-
return columns.every(column => {
|
|
1570
|
-
const columnFilters = filters[column];
|
|
1571
|
-
return Object.entries(columnFilters).every(([type, {
|
|
1572
|
-
values
|
|
1573
|
-
}]) => {
|
|
1574
|
-
const filterFn = filterFunctions[type];
|
|
1575
|
-
if (!filterFn) {
|
|
1576
|
-
throw new Error(`"${type}" filter is not implemented.`);
|
|
1577
|
-
}
|
|
1578
|
-
if (!values) return 0;
|
|
1579
|
-
const featureValue = getFeatureValue(featureIdIdx, binaryData, {
|
|
1580
|
-
type: type,
|
|
1581
|
-
column,
|
|
1582
|
-
values
|
|
1583
|
-
});
|
|
1584
|
-
if (featureValue === undefined || featureValue === null) return 0;
|
|
1585
|
-
return filterFn(values, featureValue);
|
|
1586
|
-
});
|
|
1587
|
-
});
|
|
1588
|
-
}
|
|
1589
|
-
|
|
1590
|
-
function geojsonFeatures({
|
|
1591
|
-
geojson,
|
|
1592
|
-
spatialFilter,
|
|
1593
|
-
uniqueIdProperty
|
|
1594
|
-
}) {
|
|
1595
|
-
let uniqueIdx = 0;
|
|
1596
|
-
const map = new Map();
|
|
1597
|
-
if (!spatialFilter) {
|
|
1598
|
-
return [];
|
|
1599
|
-
}
|
|
1600
|
-
for (const feature of geojson.features) {
|
|
1601
|
-
const uniqueId = uniqueIdProperty ? feature.properties[uniqueIdProperty] : ++uniqueIdx;
|
|
1602
|
-
if (!map.has(uniqueId) && intersects(spatialFilter, feature)) {
|
|
1603
|
-
map.set(uniqueId, feature.properties);
|
|
1604
|
-
}
|
|
1605
|
-
}
|
|
1606
|
-
return Array.from(map.values());
|
|
1607
|
-
}
|
|
1608
|
-
|
|
1609
|
-
// math.gl
|
|
1610
|
-
// SPDX-License-Identifier: MIT
|
|
1611
|
-
// Copyright (c) vis.gl contributors
|
|
1612
|
-
const DEFAULT_CONFIG = {
|
|
1613
|
-
EPSILON: 1e-12,
|
|
1614
|
-
debug: false,
|
|
1615
|
-
precision: 4,
|
|
1616
|
-
printTypes: false,
|
|
1617
|
-
printDegrees: false,
|
|
1618
|
-
printRowMajor: true,
|
|
1619
|
-
_cartographicRadians: false
|
|
1620
|
-
};
|
|
1621
|
-
// Configuration is truly global as of v3.6 to ensure single config even if multiple copies of math.gl
|
|
1622
|
-
// Multiple copies of config can be quite tricky to debug...
|
|
1623
|
-
globalThis.mathgl = globalThis.mathgl || {
|
|
1624
|
-
config: {
|
|
1625
|
-
...DEFAULT_CONFIG
|
|
1626
|
-
}
|
|
1627
|
-
};
|
|
1628
|
-
/**
|
|
1629
|
-
* Check if value is an "array"
|
|
1630
|
-
* Returns `true` if value is either an array or a typed array
|
|
1631
|
-
* Note: returns `false` for `ArrayBuffer` and `DataView` instances
|
|
1632
|
-
* @note isTypedArray and isNumericArray are often more useful in TypeScript
|
|
1633
|
-
*/
|
|
1634
|
-
function isArray(value) {
|
|
1635
|
-
return Array.isArray(value) || ArrayBuffer.isView(value) && !(value instanceof DataView);
|
|
1636
|
-
}
|
|
1637
|
-
function lerp(a, b, t) {
|
|
1638
|
-
if (isArray(a)) {
|
|
1639
|
-
return a.map((ai, i) => lerp(ai, b[i], t));
|
|
1640
|
-
}
|
|
1641
|
-
return t * b + (1 - t) * a;
|
|
1642
|
-
}
|
|
1643
|
-
|
|
1644
|
-
// Replacement for the external assert method to reduce bundle size
|
|
1645
|
-
// Note: We don't use the second "message" argument in calling code,
|
|
1646
|
-
// so no need to support it here
|
|
1647
|
-
function assert(condition, message) {
|
|
1648
|
-
if (!condition) {
|
|
1649
|
-
throw new Error(message || '@math.gl/web-mercator: assertion failed.');
|
|
1650
|
-
}
|
|
1651
|
-
}
|
|
1652
|
-
|
|
1653
|
-
// TODO - THE UTILITIES IN THIS FILE SHOULD BE IMPORTED FROM WEB-MERCATOR-VIEWPORT MODULE
|
|
1654
|
-
// CONSTANTS
|
|
1655
|
-
const PI = Math.PI;
|
|
1656
|
-
const PI_4 = PI / 4;
|
|
1657
|
-
const DEGREES_TO_RADIANS = PI / 180;
|
|
1658
|
-
const RADIANS_TO_DEGREES = 180 / PI;
|
|
1659
|
-
const TILE_SIZE = 512;
|
|
1660
|
-
/**
|
|
1661
|
-
* Project [lng,lat] on sphere onto [x,y] on 512*512 Mercator Zoom 0 tile.
|
|
1662
|
-
* Performs the nonlinear part of the web mercator projection.
|
|
1663
|
-
* Remaining projection is done with 4x4 matrices which also handles
|
|
1664
|
-
* perspective.
|
|
1665
|
-
*
|
|
1666
|
-
* @param lngLat - [lng, lat] coordinates
|
|
1667
|
-
* Specifies a point on the sphere to project onto the map.
|
|
1668
|
-
* @return [x,y] coordinates.
|
|
1669
|
-
*/
|
|
1670
|
-
function lngLatToWorld(lngLat) {
|
|
1671
|
-
const [lng, lat] = lngLat;
|
|
1672
|
-
assert(Number.isFinite(lng));
|
|
1673
|
-
assert(Number.isFinite(lat) && lat >= -90 && lat <= 90, 'invalid latitude');
|
|
1674
|
-
const lambda2 = lng * DEGREES_TO_RADIANS;
|
|
1675
|
-
const phi2 = lat * DEGREES_TO_RADIANS;
|
|
1676
|
-
const x = TILE_SIZE * (lambda2 + PI) / (2 * PI);
|
|
1677
|
-
const y = TILE_SIZE * (PI + Math.log(Math.tan(PI_4 + phi2 * 0.5))) / (2 * PI);
|
|
1678
|
-
return [x, y];
|
|
1679
|
-
}
|
|
1680
|
-
/**
|
|
1681
|
-
* Unproject world point [x,y] on map onto {lat, lon} on sphere
|
|
1682
|
-
*
|
|
1683
|
-
* @param xy - array with [x,y] members
|
|
1684
|
-
* representing point on projected map plane
|
|
1685
|
-
* @return - array with [x,y] of point on sphere.
|
|
1686
|
-
* Has toArray method if you need a GeoJSON Array.
|
|
1687
|
-
* Per cartographic tradition, lat and lon are specified as degrees.
|
|
1688
|
-
*/
|
|
1689
|
-
function worldToLngLat(xy) {
|
|
1690
|
-
const [x, y] = xy;
|
|
1691
|
-
const lambda2 = x / TILE_SIZE * (2 * PI) - PI;
|
|
1692
|
-
const phi2 = 2 * (Math.atan(Math.exp(y / TILE_SIZE * (2 * PI) - PI)) - PI_4);
|
|
1693
|
-
return [lambda2 * RADIANS_TO_DEGREES, phi2 * RADIANS_TO_DEGREES];
|
|
1694
|
-
}
|
|
1695
|
-
|
|
1696
|
-
const TRANSFORM_FN$1 = {
|
|
1697
|
-
Point: transformPoint$1,
|
|
1698
|
-
MultiPoint: transformMultiPoint$1,
|
|
1699
|
-
LineString: transformLineString$1,
|
|
1700
|
-
MultiLineString: transformMultiLineString$1,
|
|
1701
|
-
Polygon: transformPolygon$1,
|
|
1702
|
-
MultiPolygon: transformMultiPolygon$1
|
|
1703
|
-
};
|
|
1704
|
-
/**
|
|
1705
|
-
* Transform WGS84 coordinates to tile coords.
|
|
1706
|
-
* It's the inverse of deck.gl coordinate-transform (https://github.com/visgl/deck.gl/blob/master/modules/geo-layers/src/mvt-layer/coordinate-transform.js)
|
|
1707
|
-
*
|
|
1708
|
-
* @param geometry - any valid geojson geometry
|
|
1709
|
-
* @param bbox - geojson bbox
|
|
1710
|
-
*/
|
|
1711
|
-
function transformToTileCoords(geometry, bbox) {
|
|
1712
|
-
const [west, south, east, north] = bbox;
|
|
1713
|
-
const nw = projectFlat([west, north]);
|
|
1714
|
-
const se = projectFlat([east, south]);
|
|
1715
|
-
const projectedBbox = [nw, se];
|
|
1716
|
-
if (geometry.type === 'GeometryCollection') {
|
|
1717
|
-
throw new Error('Unsupported geometry type GeometryCollection');
|
|
1718
|
-
}
|
|
1719
|
-
const transformFn = TRANSFORM_FN$1[geometry.type];
|
|
1720
|
-
const coordinates = transformFn(geometry.coordinates, projectedBbox);
|
|
1721
|
-
return _extends({}, geometry, {
|
|
1722
|
-
coordinates
|
|
1723
|
-
});
|
|
1724
|
-
}
|
|
1725
|
-
function transformPoint$1([pointX, pointY], [nw, se]) {
|
|
1726
|
-
const x = inverseLerp(nw[0], se[0], pointX);
|
|
1727
|
-
const y = inverseLerp(nw[1], se[1], pointY);
|
|
1728
|
-
return [x, y];
|
|
1729
|
-
}
|
|
1730
|
-
function getPoints$1(geometry, bbox) {
|
|
1731
|
-
return geometry.map(g => transformPoint$1(projectFlat(g), bbox));
|
|
1732
|
-
}
|
|
1733
|
-
function transformMultiPoint$1(multiPoint, bbox) {
|
|
1734
|
-
return getPoints$1(multiPoint, bbox);
|
|
1735
|
-
}
|
|
1736
|
-
function transformLineString$1(line, bbox) {
|
|
1737
|
-
return getPoints$1(line, bbox);
|
|
1738
|
-
}
|
|
1739
|
-
function transformMultiLineString$1(multiLineString, bbox) {
|
|
1740
|
-
return multiLineString.map(lineString => transformLineString$1(lineString, bbox));
|
|
1741
|
-
}
|
|
1742
|
-
function transformPolygon$1(polygon, bbox) {
|
|
1743
|
-
return polygon.map(polygonRing => getPoints$1(polygonRing, bbox));
|
|
1744
|
-
}
|
|
1745
|
-
function transformMultiPolygon$1(multiPolygon, bbox) {
|
|
1746
|
-
return multiPolygon.map(polygon => transformPolygon$1(polygon, bbox));
|
|
1747
|
-
}
|
|
1748
|
-
function projectFlat(xyz) {
|
|
1749
|
-
return lngLatToWorld(xyz);
|
|
1750
|
-
}
|
|
1751
|
-
function inverseLerp(a, b, x) {
|
|
1752
|
-
return (x - a) / (b - a);
|
|
1753
|
-
}
|
|
1754
|
-
|
|
1755
|
-
const TRANSFORM_FN = {
|
|
1756
|
-
Point: transformPoint,
|
|
1757
|
-
MultiPoint: transformMultiPoint,
|
|
1758
|
-
LineString: transformLineString,
|
|
1759
|
-
MultiLineString: transformMultiLineString,
|
|
1760
|
-
Polygon: transformPolygon,
|
|
1761
|
-
MultiPolygon: transformMultiPolygon
|
|
1762
|
-
};
|
|
1763
|
-
/**
|
|
1764
|
-
* Transform tile coords to WGS84 coordinates.
|
|
1765
|
-
*
|
|
1766
|
-
* @param geometry - any valid geojson geometry
|
|
1767
|
-
* @param bbox - geojson bbox
|
|
1768
|
-
*/
|
|
1769
|
-
function transformTileCoordsToWGS84(geometry, bbox) {
|
|
1770
|
-
const [west, south, east, north] = bbox;
|
|
1771
|
-
const nw = lngLatToWorld([west, north]);
|
|
1772
|
-
const se = lngLatToWorld([east, south]);
|
|
1773
|
-
const projectedBbox = [nw, se];
|
|
1774
|
-
if (geometry.type === 'GeometryCollection') {
|
|
1775
|
-
throw new Error('Unsupported geometry type GeometryCollection');
|
|
1776
|
-
}
|
|
1777
|
-
const transformFn = TRANSFORM_FN[geometry.type];
|
|
1778
|
-
const coordinates = transformFn(geometry.coordinates, projectedBbox);
|
|
1779
|
-
return _extends({}, geometry, {
|
|
1780
|
-
coordinates
|
|
1781
|
-
});
|
|
1782
|
-
}
|
|
1783
|
-
function transformPoint([pointX, pointY], [nw, se]) {
|
|
1784
|
-
const x = lerp(nw[0], se[0], pointX);
|
|
1785
|
-
const y = lerp(nw[1], se[1], pointY);
|
|
1786
|
-
return worldToLngLat([x, y]);
|
|
1787
|
-
}
|
|
1788
|
-
function getPoints(geometry, bbox) {
|
|
1789
|
-
return geometry.map(g => transformPoint(g, bbox));
|
|
1790
|
-
}
|
|
1791
|
-
function transformMultiPoint(multiPoint, bbox) {
|
|
1792
|
-
return getPoints(multiPoint, bbox);
|
|
1793
|
-
}
|
|
1794
|
-
function transformLineString(line, bbox) {
|
|
1795
|
-
return getPoints(line, bbox);
|
|
1796
|
-
}
|
|
1797
|
-
function transformMultiLineString(multiLineString, bbox) {
|
|
1798
|
-
return multiLineString.map(lineString => transformLineString(lineString, bbox));
|
|
1799
|
-
}
|
|
1800
|
-
function transformPolygon(polygon, bbox) {
|
|
1801
|
-
return polygon.map(polygonRing => getPoints(polygonRing, bbox));
|
|
1802
|
-
}
|
|
1803
|
-
function transformMultiPolygon(multiPolygon, bbox) {
|
|
1804
|
-
return multiPolygon.map(polygon => transformPolygon(polygon, bbox));
|
|
1805
|
-
}
|
|
1806
|
-
|
|
1807
|
-
const FEATURE_GEOM_PROPERTY = '__geomValue';
|
|
1808
|
-
function tileFeaturesGeometries({
|
|
1809
|
-
tiles,
|
|
1810
|
-
tileFormat,
|
|
1811
|
-
spatialFilter,
|
|
1812
|
-
uniqueIdProperty,
|
|
1813
|
-
options
|
|
1814
|
-
}) {
|
|
1815
|
-
const map = new Map();
|
|
1816
|
-
for (const tile of tiles) {
|
|
1817
|
-
// Discard if it's not a visible tile (only check false value, not undefined)
|
|
1818
|
-
// or tile has not data
|
|
1819
|
-
if (tile.isVisible === false || !tile.data) {
|
|
1820
|
-
continue;
|
|
1821
|
-
}
|
|
1822
|
-
const bbox = [tile.bbox.west, tile.bbox.south, tile.bbox.east, tile.bbox.north];
|
|
1823
|
-
const bboxToGeom = bboxPolygon(bbox);
|
|
1824
|
-
const tileIsFullyVisible = booleanWithin(bboxToGeom, spatialFilter);
|
|
1825
|
-
// Clip the geometry to intersect with the tile
|
|
1826
|
-
const spatialFilterFeature = {
|
|
1827
|
-
type: 'Feature',
|
|
1828
|
-
geometry: spatialFilter,
|
|
1829
|
-
properties: {}
|
|
1830
|
-
};
|
|
1831
|
-
const clippedGeometryToIntersect = intersect(featureCollection([bboxToGeom, spatialFilterFeature]));
|
|
1832
|
-
if (!clippedGeometryToIntersect) {
|
|
1833
|
-
continue;
|
|
1834
|
-
}
|
|
1835
|
-
// We assume that MVT tileFormat uses local coordinates so we transform the geometry to intersect to tile coordinates [0..1],
|
|
1836
|
-
// while in the case of 'geojson' or binary, the geometries are already in WGS84
|
|
1837
|
-
const transformedGeometryToIntersect = tileFormat === TileFormat.MVT ? transformToTileCoords(clippedGeometryToIntersect.geometry, bbox) : clippedGeometryToIntersect.geometry;
|
|
1838
|
-
createIndicesForPoints(tile.data.points);
|
|
1839
|
-
calculateFeatures({
|
|
1840
|
-
map,
|
|
1841
|
-
tileIsFullyVisible,
|
|
1842
|
-
geometryIntersection: transformedGeometryToIntersect,
|
|
1843
|
-
data: tile.data.points,
|
|
1844
|
-
type: 'Point',
|
|
1845
|
-
bbox,
|
|
1846
|
-
tileFormat,
|
|
1847
|
-
uniqueIdProperty,
|
|
1848
|
-
options
|
|
1849
|
-
});
|
|
1850
|
-
calculateFeatures({
|
|
1851
|
-
map,
|
|
1852
|
-
tileIsFullyVisible,
|
|
1853
|
-
geometryIntersection: transformedGeometryToIntersect,
|
|
1854
|
-
data: tile.data.lines,
|
|
1855
|
-
type: 'LineString',
|
|
1856
|
-
bbox,
|
|
1857
|
-
tileFormat,
|
|
1858
|
-
uniqueIdProperty,
|
|
1859
|
-
options
|
|
1860
|
-
});
|
|
1861
|
-
calculateFeatures({
|
|
1862
|
-
map,
|
|
1863
|
-
tileIsFullyVisible,
|
|
1864
|
-
geometryIntersection: transformedGeometryToIntersect,
|
|
1865
|
-
data: tile.data.polygons,
|
|
1866
|
-
type: 'Polygon',
|
|
1867
|
-
bbox,
|
|
1868
|
-
tileFormat,
|
|
1869
|
-
uniqueIdProperty,
|
|
1870
|
-
options
|
|
1871
|
-
});
|
|
1872
|
-
}
|
|
1873
|
-
return Array.from(map.values());
|
|
1874
|
-
}
|
|
1875
|
-
function processTileFeatureProperties({
|
|
1876
|
-
map,
|
|
1877
|
-
data,
|
|
1878
|
-
startIndex,
|
|
1879
|
-
endIndex,
|
|
1880
|
-
type,
|
|
1881
|
-
bbox,
|
|
1882
|
-
tileFormat,
|
|
1883
|
-
uniqueIdProperty,
|
|
1884
|
-
storeGeometry,
|
|
1885
|
-
geometryIntersection
|
|
1886
|
-
}) {
|
|
1887
|
-
const tileProps = getPropertiesFromTile(data, startIndex);
|
|
1888
|
-
const uniquePropertyValue = getUniquePropertyValue(tileProps, uniqueIdProperty, map);
|
|
1889
|
-
if (!uniquePropertyValue || map.has(uniquePropertyValue)) {
|
|
1890
|
-
return;
|
|
1891
|
-
}
|
|
1892
|
-
let geometry = null;
|
|
1893
|
-
// Only calculate geometry if necessary
|
|
1894
|
-
if (storeGeometry || geometryIntersection) {
|
|
1895
|
-
const {
|
|
1896
|
-
positions
|
|
1897
|
-
} = data;
|
|
1898
|
-
const ringCoordinates = getRingCoordinatesFor(startIndex, endIndex, positions);
|
|
1899
|
-
geometry = getFeatureByType(ringCoordinates, type);
|
|
1900
|
-
}
|
|
1901
|
-
// If intersection is required, check before proceeding
|
|
1902
|
-
if (geometry && geometryIntersection && !intersects(geometry, geometryIntersection)) {
|
|
1903
|
-
return;
|
|
1904
|
-
}
|
|
1905
|
-
const properties = parseProperties(tileProps);
|
|
1906
|
-
// Only save geometry if necessary
|
|
1907
|
-
if (storeGeometry && geometry) {
|
|
1908
|
-
properties[FEATURE_GEOM_PROPERTY] = tileFormat === TileFormat.MVT ? transformTileCoordsToWGS84(geometry, bbox) : geometry;
|
|
1909
|
-
}
|
|
1910
|
-
map.set(uniquePropertyValue, properties);
|
|
1911
|
-
}
|
|
1912
|
-
function addIntersectedFeaturesInTile({
|
|
1913
|
-
map,
|
|
1914
|
-
data,
|
|
1915
|
-
geometryIntersection,
|
|
1916
|
-
type,
|
|
1917
|
-
bbox,
|
|
1918
|
-
tileFormat,
|
|
1919
|
-
uniqueIdProperty,
|
|
1920
|
-
options
|
|
1921
|
-
}) {
|
|
1922
|
-
const indices = getIndices(data);
|
|
1923
|
-
const storeGeometry = (options == null ? void 0 : options.storeGeometry) || false;
|
|
1924
|
-
for (let i = 0; i < indices.length - 1; i++) {
|
|
1925
|
-
const startIndex = indices[i];
|
|
1926
|
-
const endIndex = indices[i + 1];
|
|
1927
|
-
processTileFeatureProperties({
|
|
1928
|
-
map,
|
|
1929
|
-
data,
|
|
1930
|
-
startIndex,
|
|
1931
|
-
endIndex,
|
|
1932
|
-
type,
|
|
1933
|
-
bbox,
|
|
1934
|
-
tileFormat,
|
|
1935
|
-
uniqueIdProperty,
|
|
1936
|
-
storeGeometry,
|
|
1937
|
-
geometryIntersection
|
|
1938
|
-
});
|
|
1939
|
-
}
|
|
1940
|
-
}
|
|
1941
|
-
function getIndices(data) {
|
|
1942
|
-
let indices;
|
|
1943
|
-
switch (data.type) {
|
|
1944
|
-
case 'Point':
|
|
1945
|
-
// @ts-expect-error Missing or changed types?
|
|
1946
|
-
indices = data.pointIndices;
|
|
1947
|
-
break;
|
|
1948
|
-
case 'LineString':
|
|
1949
|
-
indices = data.pathIndices;
|
|
1950
|
-
break;
|
|
1951
|
-
case 'Polygon':
|
|
1952
|
-
indices = data.primitivePolygonIndices;
|
|
1953
|
-
break;
|
|
1954
|
-
default:
|
|
1955
|
-
throw new Error(`Unexpected type, "${data.type}"`);
|
|
1956
|
-
}
|
|
1957
|
-
return indices.value;
|
|
1958
|
-
}
|
|
1959
|
-
function getFeatureId(data, startIndex) {
|
|
1960
|
-
return data.featureIds.value[startIndex];
|
|
1961
|
-
}
|
|
1962
|
-
function getPropertiesFromTile(data, startIndex) {
|
|
1963
|
-
var _fields$featureId;
|
|
1964
|
-
const featureId = getFeatureId(data, startIndex);
|
|
1965
|
-
const {
|
|
1966
|
-
properties,
|
|
1967
|
-
numericProps,
|
|
1968
|
-
fields
|
|
1969
|
-
} = data;
|
|
1970
|
-
const result = {
|
|
1971
|
-
uniqueId: fields == null || (_fields$featureId = fields[featureId]) == null ? void 0 : _fields$featureId.id,
|
|
1972
|
-
properties: properties[featureId],
|
|
1973
|
-
numericProps: {}
|
|
1974
|
-
};
|
|
1975
|
-
for (const key in numericProps) {
|
|
1976
|
-
result.numericProps[key] = numericProps[key].value[startIndex];
|
|
1977
|
-
}
|
|
1978
|
-
return result;
|
|
1979
|
-
}
|
|
1980
|
-
function parseProperties(tileProps) {
|
|
1981
|
-
const {
|
|
1982
|
-
properties,
|
|
1983
|
-
numericProps
|
|
1984
|
-
} = tileProps;
|
|
1985
|
-
return Object.assign({}, properties, numericProps);
|
|
1986
|
-
}
|
|
1987
|
-
function getUniquePropertyValue(tileProps, uniqueIdProperty, map) {
|
|
1988
|
-
if (uniqueIdProperty) {
|
|
1989
|
-
return getValueFromTileProps(tileProps, uniqueIdProperty);
|
|
1990
|
-
}
|
|
1991
|
-
if (tileProps.uniqueId) {
|
|
1992
|
-
return tileProps.uniqueId;
|
|
1993
|
-
}
|
|
1994
|
-
const artificialId = map.size + 1; // a counter, assumed as a valid new id
|
|
1995
|
-
return getValueFromTileProps(tileProps, 'cartodb_id') || getValueFromTileProps(tileProps, 'geoid') || artificialId;
|
|
1996
|
-
}
|
|
1997
|
-
function getValueFromTileProps(tileProps, propertyName) {
|
|
1998
|
-
const {
|
|
1999
|
-
properties,
|
|
2000
|
-
numericProps
|
|
2001
|
-
} = tileProps;
|
|
2002
|
-
return numericProps[propertyName] || properties[propertyName];
|
|
2003
|
-
}
|
|
2004
|
-
function getFeatureByType(coordinates, type) {
|
|
2005
|
-
switch (type) {
|
|
2006
|
-
case 'Polygon':
|
|
2007
|
-
return {
|
|
2008
|
-
type: 'Polygon',
|
|
2009
|
-
coordinates: [coordinates]
|
|
2010
|
-
};
|
|
2011
|
-
case 'LineString':
|
|
2012
|
-
return {
|
|
2013
|
-
type: 'LineString',
|
|
2014
|
-
coordinates
|
|
2015
|
-
};
|
|
2016
|
-
case 'Point':
|
|
2017
|
-
return {
|
|
2018
|
-
type: 'Point',
|
|
2019
|
-
coordinates: coordinates[0]
|
|
2020
|
-
};
|
|
2021
|
-
default:
|
|
2022
|
-
throw new Error('Invalid geometry type');
|
|
2023
|
-
}
|
|
2024
|
-
}
|
|
2025
|
-
function getRingCoordinatesFor(startIndex, endIndex, positions) {
|
|
2026
|
-
const ringCoordinates = [];
|
|
2027
|
-
for (let j = startIndex; j < endIndex; j++) {
|
|
2028
|
-
ringCoordinates.push(Array.from(positions.value.subarray(j * positions.size, (j + 1) * positions.size)));
|
|
2029
|
-
}
|
|
2030
|
-
return ringCoordinates;
|
|
2031
|
-
}
|
|
2032
|
-
function calculateFeatures({
|
|
2033
|
-
map,
|
|
2034
|
-
tileIsFullyVisible,
|
|
2035
|
-
geometryIntersection,
|
|
2036
|
-
data,
|
|
2037
|
-
type,
|
|
2038
|
-
bbox,
|
|
2039
|
-
tileFormat,
|
|
2040
|
-
uniqueIdProperty,
|
|
2041
|
-
options
|
|
2042
|
-
}) {
|
|
2043
|
-
if (!(data != null && data.properties.length)) {
|
|
2044
|
-
return;
|
|
2045
|
-
}
|
|
2046
|
-
if (tileIsFullyVisible) {
|
|
2047
|
-
addAllFeaturesInTile({
|
|
2048
|
-
map,
|
|
2049
|
-
data,
|
|
2050
|
-
type,
|
|
2051
|
-
bbox,
|
|
2052
|
-
tileFormat,
|
|
2053
|
-
uniqueIdProperty,
|
|
2054
|
-
options
|
|
2055
|
-
});
|
|
2056
|
-
} else {
|
|
2057
|
-
addIntersectedFeaturesInTile({
|
|
2058
|
-
map,
|
|
2059
|
-
data,
|
|
2060
|
-
geometryIntersection,
|
|
2061
|
-
type,
|
|
2062
|
-
bbox,
|
|
2063
|
-
tileFormat,
|
|
2064
|
-
uniqueIdProperty,
|
|
2065
|
-
options
|
|
2066
|
-
});
|
|
2067
|
-
}
|
|
2068
|
-
}
|
|
2069
|
-
function addAllFeaturesInTile({
|
|
2070
|
-
map,
|
|
2071
|
-
data,
|
|
2072
|
-
type,
|
|
2073
|
-
bbox,
|
|
2074
|
-
tileFormat,
|
|
2075
|
-
uniqueIdProperty,
|
|
2076
|
-
options
|
|
2077
|
-
}) {
|
|
2078
|
-
const indices = getIndices(data);
|
|
2079
|
-
const storeGeometry = (options == null ? void 0 : options.storeGeometry) || false;
|
|
2080
|
-
for (let i = 0; i < indices.length - 1; i++) {
|
|
2081
|
-
const startIndex = indices[i];
|
|
2082
|
-
const endIndex = indices[i + 1];
|
|
2083
|
-
processTileFeatureProperties({
|
|
2084
|
-
map,
|
|
2085
|
-
data,
|
|
2086
|
-
startIndex,
|
|
2087
|
-
endIndex,
|
|
2088
|
-
type,
|
|
2089
|
-
bbox,
|
|
2090
|
-
tileFormat,
|
|
2091
|
-
uniqueIdProperty,
|
|
2092
|
-
storeGeometry
|
|
2093
|
-
});
|
|
2094
|
-
}
|
|
2095
|
-
}
|
|
2096
|
-
function createIndicesForPoints(data) {
|
|
2097
|
-
const featureIds = data.featureIds.value;
|
|
2098
|
-
const lastFeatureId = featureIds[featureIds.length - 1];
|
|
2099
|
-
const PointIndicesArray = featureIds.constructor;
|
|
2100
|
-
const pointIndices = {
|
|
2101
|
-
value: new PointIndicesArray(featureIds.length + 1),
|
|
2102
|
-
size: 1
|
|
2103
|
-
};
|
|
2104
|
-
pointIndices.value.set(featureIds);
|
|
2105
|
-
pointIndices.value.set([lastFeatureId + 1], featureIds.length);
|
|
2106
|
-
// @ts-expect-error Missing or changed types?
|
|
2107
|
-
data.pointIndices = pointIndices;
|
|
2108
|
-
}
|
|
2109
|
-
|
|
2110
|
-
// a tile is an array [x,y,z]
|
|
2111
|
-
var d2r = Math.PI / 180,
|
|
2112
|
-
r2d = 180 / Math.PI;
|
|
2113
|
-
function tileToBBOX(tile) {
|
|
2114
|
-
var e = tile2lon(tile[0] + 1, tile[2]);
|
|
2115
|
-
var w = tile2lon(tile[0], tile[2]);
|
|
2116
|
-
var s = tile2lat(tile[1] + 1, tile[2]);
|
|
2117
|
-
var n = tile2lat(tile[1], tile[2]);
|
|
2118
|
-
return [w, s, e, n];
|
|
2119
|
-
}
|
|
2120
|
-
function tileToGeoJSON(tile) {
|
|
2121
|
-
var bbox = tileToBBOX(tile);
|
|
2122
|
-
var poly = {
|
|
2123
|
-
type: 'Polygon',
|
|
2124
|
-
coordinates: [[[bbox[0], bbox[1]], [bbox[0], bbox[3]], [bbox[2], bbox[3]], [bbox[2], bbox[1]], [bbox[0], bbox[1]]]]
|
|
2125
|
-
};
|
|
2126
|
-
return poly;
|
|
2127
|
-
}
|
|
2128
|
-
function tile2lon(x, z) {
|
|
2129
|
-
return x / Math.pow(2, z) * 360 - 180;
|
|
2130
|
-
}
|
|
2131
|
-
function tile2lat(y, z) {
|
|
2132
|
-
var n = Math.PI - 2 * Math.PI * y / Math.pow(2, z);
|
|
2133
|
-
return r2d * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)));
|
|
2134
|
-
}
|
|
2135
|
-
function pointToTile(lon, lat, z) {
|
|
2136
|
-
var tile = pointToTileFraction(lon, lat, z);
|
|
2137
|
-
tile[0] = Math.floor(tile[0]);
|
|
2138
|
-
tile[1] = Math.floor(tile[1]);
|
|
2139
|
-
return tile;
|
|
2140
|
-
}
|
|
2141
|
-
function getChildren(tile) {
|
|
2142
|
-
return [[tile[0] * 2, tile[1] * 2, tile[2] + 1], [tile[0] * 2 + 1, tile[1] * 2, tile[2] + 1], [tile[0] * 2 + 1, tile[1] * 2 + 1, tile[2] + 1], [tile[0] * 2, tile[1] * 2 + 1, tile[2] + 1]];
|
|
2143
|
-
}
|
|
2144
|
-
function getParent(tile) {
|
|
2145
|
-
// top left
|
|
2146
|
-
if (tile[0] % 2 === 0 && tile[1] % 2 === 0) {
|
|
2147
|
-
return [tile[0] / 2, tile[1] / 2, tile[2] - 1];
|
|
2148
|
-
}
|
|
2149
|
-
// bottom left
|
|
2150
|
-
else if (tile[0] % 2 === 0 && !tile[1] % 2 === 0) {
|
|
2151
|
-
return [tile[0] / 2, (tile[1] - 1) / 2, tile[2] - 1];
|
|
2152
|
-
}
|
|
2153
|
-
// top right
|
|
2154
|
-
else if (!tile[0] % 2 === 0 && tile[1] % 2 === 0) {
|
|
2155
|
-
return [(tile[0] - 1) / 2, tile[1] / 2, tile[2] - 1];
|
|
2156
|
-
}
|
|
2157
|
-
// bottom right
|
|
2158
|
-
else {
|
|
2159
|
-
return [(tile[0] - 1) / 2, (tile[1] - 1) / 2, tile[2] - 1];
|
|
2160
|
-
}
|
|
2161
|
-
}
|
|
2162
|
-
function getSiblings(tile) {
|
|
2163
|
-
return getChildren(getParent(tile));
|
|
2164
|
-
}
|
|
2165
|
-
function hasSiblings(tile, tiles) {
|
|
2166
|
-
var siblings = getSiblings(tile);
|
|
2167
|
-
for (var i = 0; i < siblings.length; i++) {
|
|
2168
|
-
if (!hasTile(tiles, siblings[i])) return false;
|
|
2169
|
-
}
|
|
2170
|
-
return true;
|
|
2171
|
-
}
|
|
2172
|
-
function hasTile(tiles, tile) {
|
|
2173
|
-
for (var i = 0; i < tiles.length; i++) {
|
|
2174
|
-
if (tilesEqual(tiles[i], tile)) return true;
|
|
2175
|
-
}
|
|
2176
|
-
return false;
|
|
2177
|
-
}
|
|
2178
|
-
function tilesEqual(tile1, tile2) {
|
|
2179
|
-
return tile1[0] === tile2[0] && tile1[1] === tile2[1] && tile1[2] === tile2[2];
|
|
2180
|
-
}
|
|
2181
|
-
function tileToQuadkey(tile) {
|
|
2182
|
-
var index = '';
|
|
2183
|
-
for (var z = tile[2]; z > 0; z--) {
|
|
2184
|
-
var b = 0;
|
|
2185
|
-
var mask = 1 << z - 1;
|
|
2186
|
-
if ((tile[0] & mask) !== 0) b++;
|
|
2187
|
-
if ((tile[1] & mask) !== 0) b += 2;
|
|
2188
|
-
index += b.toString();
|
|
2189
|
-
}
|
|
2190
|
-
return index;
|
|
2191
|
-
}
|
|
2192
|
-
function quadkeyToTile(quadkey) {
|
|
2193
|
-
var x = 0;
|
|
2194
|
-
var y = 0;
|
|
2195
|
-
var z = quadkey.length;
|
|
2196
|
-
for (var i = z; i > 0; i--) {
|
|
2197
|
-
var mask = 1 << i - 1;
|
|
2198
|
-
switch (quadkey[z - i]) {
|
|
2199
|
-
case '0':
|
|
2200
|
-
break;
|
|
2201
|
-
case '1':
|
|
2202
|
-
x |= mask;
|
|
2203
|
-
break;
|
|
2204
|
-
case '2':
|
|
2205
|
-
y |= mask;
|
|
2206
|
-
break;
|
|
2207
|
-
case '3':
|
|
2208
|
-
x |= mask;
|
|
2209
|
-
y |= mask;
|
|
2210
|
-
break;
|
|
2211
|
-
}
|
|
2212
|
-
}
|
|
2213
|
-
return [x, y, z];
|
|
2214
|
-
}
|
|
2215
|
-
function bboxToTile(bboxCoords) {
|
|
2216
|
-
var min = pointToTile(bboxCoords[0], bboxCoords[1], 32);
|
|
2217
|
-
var max = pointToTile(bboxCoords[2], bboxCoords[3], 32);
|
|
2218
|
-
var bbox = [min[0], min[1], max[0], max[1]];
|
|
2219
|
-
var z = getBboxZoom(bbox);
|
|
2220
|
-
if (z === 0) return [0, 0, 0];
|
|
2221
|
-
var x = bbox[0] >>> 32 - z;
|
|
2222
|
-
var y = bbox[1] >>> 32 - z;
|
|
2223
|
-
return [x, y, z];
|
|
2224
|
-
}
|
|
2225
|
-
function getBboxZoom(bbox) {
|
|
2226
|
-
var MAX_ZOOM = 28;
|
|
2227
|
-
for (var z = 0; z < MAX_ZOOM; z++) {
|
|
2228
|
-
var mask = 1 << 32 - (z + 1);
|
|
2229
|
-
if ((bbox[0] & mask) != (bbox[2] & mask) || (bbox[1] & mask) != (bbox[3] & mask)) {
|
|
2230
|
-
return z;
|
|
2231
|
-
}
|
|
2232
|
-
}
|
|
2233
|
-
return MAX_ZOOM;
|
|
2234
|
-
}
|
|
2235
|
-
function pointToTileFraction(lon, lat, z) {
|
|
2236
|
-
var sin = Math.sin(lat * d2r),
|
|
2237
|
-
z2 = Math.pow(2, z),
|
|
2238
|
-
x = z2 * (lon / 360 + 0.5),
|
|
2239
|
-
y = z2 * (0.5 - 0.25 * Math.log((1 + sin) / (1 - sin)) / Math.PI);
|
|
2240
|
-
return [x, y, z];
|
|
2241
|
-
}
|
|
2242
|
-
var tilebelt = {
|
|
2243
|
-
tileToGeoJSON: tileToGeoJSON,
|
|
2244
|
-
tileToBBOX: tileToBBOX,
|
|
2245
|
-
getChildren: getChildren,
|
|
2246
|
-
getParent: getParent,
|
|
2247
|
-
getSiblings: getSiblings,
|
|
2248
|
-
hasTile: hasTile,
|
|
2249
|
-
hasSiblings: hasSiblings,
|
|
2250
|
-
tilesEqual: tilesEqual,
|
|
2251
|
-
tileToQuadkey: tileToQuadkey,
|
|
2252
|
-
quadkeyToTile: quadkeyToTile,
|
|
2253
|
-
pointToTile: pointToTile,
|
|
2254
|
-
bboxToTile: bboxToTile,
|
|
2255
|
-
pointToTileFraction: pointToTileFraction
|
|
2256
|
-
};
|
|
2257
|
-
|
|
2258
|
-
/**
|
|
2259
|
-
* Given a geometry, create cells and return them in their raw form,
|
|
2260
|
-
* as an array of cell identifiers.
|
|
2261
|
-
*
|
|
2262
|
-
* @alias tiles
|
|
2263
|
-
* @param {Object} geom GeoJSON geometry
|
|
2264
|
-
* @param {Object} limits an object with min_zoom and max_zoom properties
|
|
2265
|
-
* specifying the minimum and maximum level to be tiled.
|
|
2266
|
-
* @returns {Array<Array<number>>} An array of tiles given as [x, y, z] arrays
|
|
2267
|
-
*/
|
|
2268
|
-
var tiles = getTiles;
|
|
2269
|
-
function getTiles(geom, limits) {
|
|
2270
|
-
var i,
|
|
2271
|
-
tile,
|
|
2272
|
-
coords = geom.coordinates,
|
|
2273
|
-
maxZoom = limits.max_zoom,
|
|
2274
|
-
tileHash = {},
|
|
2275
|
-
tiles = [];
|
|
2276
|
-
if (geom.type === 'Point') {
|
|
2277
|
-
return [tilebelt.pointToTile(coords[0], coords[1], maxZoom)];
|
|
2278
|
-
} else if (geom.type === 'MultiPoint') {
|
|
2279
|
-
for (i = 0; i < coords.length; i++) {
|
|
2280
|
-
tile = tilebelt.pointToTile(coords[i][0], coords[i][1], maxZoom);
|
|
2281
|
-
tileHash[toID(tile[0], tile[1], tile[2])] = true;
|
|
2282
|
-
}
|
|
2283
|
-
} else if (geom.type === 'LineString') {
|
|
2284
|
-
lineCover(tileHash, coords, maxZoom);
|
|
2285
|
-
} else if (geom.type === 'MultiLineString') {
|
|
2286
|
-
for (i = 0; i < coords.length; i++) {
|
|
2287
|
-
lineCover(tileHash, coords[i], maxZoom);
|
|
2288
|
-
}
|
|
2289
|
-
} else if (geom.type === 'Polygon') {
|
|
2290
|
-
polygonCover(tileHash, tiles, coords, maxZoom);
|
|
2291
|
-
} else if (geom.type === 'MultiPolygon') {
|
|
2292
|
-
for (i = 0; i < coords.length; i++) {
|
|
2293
|
-
polygonCover(tileHash, tiles, coords[i], maxZoom);
|
|
2294
|
-
}
|
|
2295
|
-
} else {
|
|
2296
|
-
throw new Error('Geometry type not implemented');
|
|
2297
|
-
}
|
|
2298
|
-
if (limits.min_zoom !== maxZoom) {
|
|
2299
|
-
// sync tile hash and tile array so that both contain the same tiles
|
|
2300
|
-
var len = tiles.length;
|
|
2301
|
-
appendHashTiles(tileHash, tiles);
|
|
2302
|
-
for (i = 0; i < len; i++) {
|
|
2303
|
-
var t = tiles[i];
|
|
2304
|
-
tileHash[toID(t[0], t[1], t[2])] = true;
|
|
2305
|
-
}
|
|
2306
|
-
return mergeTiles(tileHash, tiles, limits);
|
|
2307
|
-
}
|
|
2308
|
-
appendHashTiles(tileHash, tiles);
|
|
2309
|
-
return tiles;
|
|
2310
|
-
}
|
|
2311
|
-
function mergeTiles(tileHash, tiles, limits) {
|
|
2312
|
-
var mergedTiles = [];
|
|
2313
|
-
for (var z = limits.max_zoom; z > limits.min_zoom; z--) {
|
|
2314
|
-
var parentTileHash = {};
|
|
2315
|
-
var parentTiles = [];
|
|
2316
|
-
for (var i = 0; i < tiles.length; i++) {
|
|
2317
|
-
var t = tiles[i];
|
|
2318
|
-
if (t[0] % 2 === 0 && t[1] % 2 === 0) {
|
|
2319
|
-
var id2 = toID(t[0] + 1, t[1], z),
|
|
2320
|
-
id3 = toID(t[0], t[1] + 1, z),
|
|
2321
|
-
id4 = toID(t[0] + 1, t[1] + 1, z);
|
|
2322
|
-
if (tileHash[id2] && tileHash[id3] && tileHash[id4]) {
|
|
2323
|
-
tileHash[toID(t[0], t[1], t[2])] = false;
|
|
2324
|
-
tileHash[id2] = false;
|
|
2325
|
-
tileHash[id3] = false;
|
|
2326
|
-
tileHash[id4] = false;
|
|
2327
|
-
var parentTile = [t[0] / 2, t[1] / 2, z - 1];
|
|
2328
|
-
if (z - 1 === limits.min_zoom) mergedTiles.push(parentTile);else {
|
|
2329
|
-
parentTileHash[toID(t[0] / 2, t[1] / 2, z - 1)] = true;
|
|
2330
|
-
parentTiles.push(parentTile);
|
|
2331
|
-
}
|
|
2332
|
-
}
|
|
2333
|
-
}
|
|
2334
|
-
}
|
|
2335
|
-
for (i = 0; i < tiles.length; i++) {
|
|
2336
|
-
t = tiles[i];
|
|
2337
|
-
if (tileHash[toID(t[0], t[1], t[2])]) mergedTiles.push(t);
|
|
2338
|
-
}
|
|
2339
|
-
tileHash = parentTileHash;
|
|
2340
|
-
tiles = parentTiles;
|
|
2341
|
-
}
|
|
2342
|
-
return mergedTiles;
|
|
2343
|
-
}
|
|
2344
|
-
function polygonCover(tileHash, tileArray, geom, zoom) {
|
|
2345
|
-
var intersections = [];
|
|
2346
|
-
for (var i = 0; i < geom.length; i++) {
|
|
2347
|
-
var ring = [];
|
|
2348
|
-
lineCover(tileHash, geom[i], zoom, ring);
|
|
2349
|
-
for (var j = 0, len = ring.length, k = len - 1; j < len; k = j++) {
|
|
2350
|
-
var m = (j + 1) % len;
|
|
2351
|
-
var y = ring[j][1];
|
|
2352
|
-
|
|
2353
|
-
// add interesction if it's not local extremum or duplicate
|
|
2354
|
-
if ((y > ring[k][1] || y > ring[m][1]) && (
|
|
2355
|
-
// not local minimum
|
|
2356
|
-
y < ring[k][1] || y < ring[m][1]) &&
|
|
2357
|
-
// not local maximum
|
|
2358
|
-
y !== ring[m][1]) intersections.push(ring[j]);
|
|
2359
|
-
}
|
|
2360
|
-
}
|
|
2361
|
-
intersections.sort(compareTiles); // sort by y, then x
|
|
2362
|
-
|
|
2363
|
-
for (i = 0; i < intersections.length; i += 2) {
|
|
2364
|
-
// fill tiles between pairs of intersections
|
|
2365
|
-
y = intersections[i][1];
|
|
2366
|
-
for (var x = intersections[i][0] + 1; x < intersections[i + 1][0]; x++) {
|
|
2367
|
-
var id = toID(x, y, zoom);
|
|
2368
|
-
if (!tileHash[id]) {
|
|
2369
|
-
tileArray.push([x, y, zoom]);
|
|
2370
|
-
}
|
|
2371
|
-
}
|
|
2372
|
-
}
|
|
2373
|
-
}
|
|
2374
|
-
function compareTiles(a, b) {
|
|
2375
|
-
return a[1] - b[1] || a[0] - b[0];
|
|
2376
|
-
}
|
|
2377
|
-
function lineCover(tileHash, coords, maxZoom, ring) {
|
|
2378
|
-
var prevX, prevY;
|
|
2379
|
-
for (var i = 0; i < coords.length - 1; i++) {
|
|
2380
|
-
var start = tilebelt.pointToTileFraction(coords[i][0], coords[i][1], maxZoom),
|
|
2381
|
-
stop = tilebelt.pointToTileFraction(coords[i + 1][0], coords[i + 1][1], maxZoom),
|
|
2382
|
-
x0 = start[0],
|
|
2383
|
-
y0 = start[1],
|
|
2384
|
-
x1 = stop[0],
|
|
2385
|
-
y1 = stop[1],
|
|
2386
|
-
dx = x1 - x0,
|
|
2387
|
-
dy = y1 - y0;
|
|
2388
|
-
if (dy === 0 && dx === 0) continue;
|
|
2389
|
-
var sx = dx > 0 ? 1 : -1,
|
|
2390
|
-
sy = dy > 0 ? 1 : -1,
|
|
2391
|
-
x = Math.floor(x0),
|
|
2392
|
-
y = Math.floor(y0),
|
|
2393
|
-
tMaxX = dx === 0 ? Infinity : Math.abs(((dx > 0 ? 1 : 0) + x - x0) / dx),
|
|
2394
|
-
tMaxY = dy === 0 ? Infinity : Math.abs(((dy > 0 ? 1 : 0) + y - y0) / dy),
|
|
2395
|
-
tdx = Math.abs(sx / dx),
|
|
2396
|
-
tdy = Math.abs(sy / dy);
|
|
2397
|
-
if (x !== prevX || y !== prevY) {
|
|
2398
|
-
tileHash[toID(x, y, maxZoom)] = true;
|
|
2399
|
-
if (ring && y !== prevY) ring.push([x, y]);
|
|
2400
|
-
prevX = x;
|
|
2401
|
-
prevY = y;
|
|
2402
|
-
}
|
|
2403
|
-
while (tMaxX < 1 || tMaxY < 1) {
|
|
2404
|
-
if (tMaxX < tMaxY) {
|
|
2405
|
-
tMaxX += tdx;
|
|
2406
|
-
x += sx;
|
|
2407
|
-
} else {
|
|
2408
|
-
tMaxY += tdy;
|
|
2409
|
-
y += sy;
|
|
2410
|
-
}
|
|
2411
|
-
tileHash[toID(x, y, maxZoom)] = true;
|
|
2412
|
-
if (ring && y !== prevY) ring.push([x, y]);
|
|
2413
|
-
prevX = x;
|
|
2414
|
-
prevY = y;
|
|
2415
|
-
}
|
|
2416
|
-
}
|
|
2417
|
-
if (ring && y === ring[0][1]) ring.pop();
|
|
2418
|
-
}
|
|
2419
|
-
function appendHashTiles(hash, tiles) {
|
|
2420
|
-
var keys = Object.keys(hash);
|
|
2421
|
-
for (var i = 0; i < keys.length; i++) {
|
|
2422
|
-
tiles.push(fromID(+keys[i]));
|
|
2423
|
-
}
|
|
2424
|
-
}
|
|
2425
|
-
function toID(x, y, z) {
|
|
2426
|
-
var dim = 2 * (1 << z);
|
|
2427
|
-
return (dim * y + x) * 32 + z;
|
|
2428
|
-
}
|
|
2429
|
-
function fromID(id) {
|
|
2430
|
-
var z = id % 32,
|
|
2431
|
-
dim = 2 * (1 << z),
|
|
2432
|
-
xy = (id - z) / 32,
|
|
2433
|
-
x = xy % dim,
|
|
2434
|
-
y = (xy - x) / dim % dim;
|
|
2435
|
-
return [x, y, z];
|
|
2436
|
-
}
|
|
2437
|
-
|
|
2438
|
-
const B = [0x5555555555555555n, 0x3333333333333333n, 0x0f0f0f0f0f0f0f0fn, 0x00ff00ff00ff00ffn, 0x0000ffff0000ffffn, 0x00000000ffffffffn];
|
|
2439
|
-
const S = [0n, 1n, 2n, 4n, 8n, 16n];
|
|
2440
|
-
function tileToCell(tile) {
|
|
2441
|
-
if (tile.z < 0 || tile.z > 26) {
|
|
2442
|
-
throw new Error('Wrong zoom');
|
|
2443
|
-
}
|
|
2444
|
-
const z = BigInt(tile.z);
|
|
2445
|
-
let x = BigInt(tile.x) << 32n - z;
|
|
2446
|
-
let y = BigInt(tile.y) << 32n - z;
|
|
2447
|
-
for (let i = 0; i < 5; i++) {
|
|
2448
|
-
const s = S[5 - i];
|
|
2449
|
-
const b = B[4 - i];
|
|
2450
|
-
x = (x | x << s) & b;
|
|
2451
|
-
y = (y | y << s) & b;
|
|
2452
|
-
}
|
|
2453
|
-
const quadbin = 0x4000000000000000n | 1n << 59n |
|
|
2454
|
-
// | (mode << 59) | (mode_dep << 57)
|
|
2455
|
-
z << 52n | (x | y << 1n) >> 12n | 0xfffffffffffffn >> z * 2n;
|
|
2456
|
-
return quadbin;
|
|
2457
|
-
}
|
|
2458
|
-
function getResolution$1(quadbin) {
|
|
2459
|
-
return quadbin >> 52n & 0x1fn;
|
|
2460
|
-
}
|
|
2461
|
-
function geometryToCells(geometry, resolution) {
|
|
2462
|
-
const zoom = Number(resolution);
|
|
2463
|
-
return tiles(geometry, {
|
|
2464
|
-
min_zoom: zoom,
|
|
2465
|
-
max_zoom: zoom
|
|
2466
|
-
}).map(([x, y, z]) => tileToCell({
|
|
2467
|
-
x,
|
|
2468
|
-
y,
|
|
2469
|
-
z
|
|
2470
|
-
}));
|
|
2471
|
-
}
|
|
2472
|
-
|
|
2473
|
-
function tileFeaturesSpatialIndex({
|
|
2474
|
-
tiles,
|
|
2475
|
-
spatialFilter,
|
|
2476
|
-
spatialDataColumn,
|
|
2477
|
-
spatialDataType
|
|
2478
|
-
}) {
|
|
2479
|
-
const map = new Map();
|
|
2480
|
-
const spatialIndex = getSpatialIndex(spatialDataType);
|
|
2481
|
-
const resolution = getResolution(tiles, spatialIndex);
|
|
2482
|
-
const spatialIndexIDName = spatialDataColumn ? spatialDataColumn : spatialIndex;
|
|
2483
|
-
if (!resolution) {
|
|
2484
|
-
return [];
|
|
2485
|
-
}
|
|
2486
|
-
const cells = getCellsCoverGeometry(spatialFilter, spatialIndex, resolution);
|
|
2487
|
-
if (!(cells != null && cells.length)) {
|
|
2488
|
-
return [];
|
|
2489
|
-
}
|
|
2490
|
-
// We transform cells to Set to improve the performace
|
|
2491
|
-
const cellsSet = new Set(cells);
|
|
2492
|
-
for (const tile of tiles) {
|
|
2493
|
-
if (tile.isVisible === false || !tile.data) {
|
|
2494
|
-
continue;
|
|
2495
|
-
}
|
|
2496
|
-
tile.data.forEach(d => {
|
|
2497
|
-
if (cellsSet.has(d.id)) {
|
|
2498
|
-
map.set(d.id, _extends({}, d.properties, {
|
|
2499
|
-
[spatialIndexIDName]: d.id
|
|
2500
|
-
}));
|
|
2501
|
-
}
|
|
2502
|
-
});
|
|
2503
|
-
}
|
|
2504
|
-
return Array.from(map.values());
|
|
2505
|
-
}
|
|
2506
|
-
function getResolution(tiles, spatialIndex) {
|
|
2507
|
-
var _tiles$find;
|
|
2508
|
-
const data = (_tiles$find = tiles.find(tile => {
|
|
2509
|
-
var _tile$data;
|
|
2510
|
-
return (_tile$data = tile.data) == null ? void 0 : _tile$data.length;
|
|
2511
|
-
})) == null ? void 0 : _tiles$find.data;
|
|
2512
|
-
if (!data) {
|
|
2513
|
-
return;
|
|
2514
|
-
}
|
|
2515
|
-
if (spatialIndex === SpatialIndex.QUADBIN) {
|
|
2516
|
-
return Number(getResolution$1(data[0].id));
|
|
2517
|
-
}
|
|
2518
|
-
if (spatialIndex === SpatialIndex.H3) {
|
|
2519
|
-
return getResolution$2(data[0].id);
|
|
2520
|
-
}
|
|
2521
|
-
}
|
|
2522
|
-
const bboxWest = [-180, -90, 0, 90];
|
|
2523
|
-
const bboxEast = [0, -90, 180, 90];
|
|
2524
|
-
function getCellsCoverGeometry(geometry, spatialIndex, resolution) {
|
|
2525
|
-
if (spatialIndex === SpatialIndex.QUADBIN) {
|
|
2526
|
-
// @ts-expect-error TODO: Probably ought to be stricter about number vs. bigint types in this file.
|
|
2527
|
-
return geometryToCells(geometry, resolution);
|
|
2528
|
-
}
|
|
2529
|
-
if (spatialIndex === SpatialIndex.H3) {
|
|
2530
|
-
// The current H3 polyfill algorithm can't deal with polygon segments of greater than 180 degrees longitude
|
|
2531
|
-
// so we clip the geometry to be sure that none of them is greater than 180 degrees
|
|
2532
|
-
// https://github.com/uber/h3-js/issues/24#issuecomment-431893796
|
|
2533
|
-
return polygonToCells(bboxClip(geometry, bboxWest).geometry.coordinates, resolution, true).concat(polygonToCells(bboxClip(geometry, bboxEast).geometry.coordinates, resolution, true));
|
|
2534
|
-
}
|
|
2535
|
-
}
|
|
2536
|
-
function getSpatialIndex(spatialDataType) {
|
|
2537
|
-
switch (spatialDataType) {
|
|
2538
|
-
case 'h3':
|
|
2539
|
-
return SpatialIndex.H3;
|
|
2540
|
-
case 'quadbin':
|
|
2541
|
-
return SpatialIndex.QUADBIN;
|
|
2542
|
-
default:
|
|
2543
|
-
throw new Error('Unexpected spatial data type');
|
|
2544
|
-
}
|
|
2545
|
-
}
|
|
2546
|
-
|
|
2547
|
-
/** @internalRemarks Source: @carto/react-core */
|
|
2548
|
-
function tileFeatures({
|
|
2549
|
-
tiles,
|
|
2550
|
-
spatialFilter,
|
|
2551
|
-
uniqueIdProperty,
|
|
2552
|
-
tileFormat,
|
|
2553
|
-
spatialDataColumn = DEFAULT_GEO_COLUMN,
|
|
2554
|
-
spatialDataType,
|
|
2555
|
-
options = {}
|
|
2556
|
-
}) {
|
|
2557
|
-
// TODO(cleanup): Is an empty response the expected result when spatialFilter
|
|
2558
|
-
// is omitted? Why not make the parameter required, or return the full input?
|
|
2559
|
-
if (!spatialFilter) {
|
|
2560
|
-
return [];
|
|
2561
|
-
}
|
|
2562
|
-
if (spatialDataType !== 'geo') {
|
|
2563
|
-
return tileFeaturesSpatialIndex({
|
|
2564
|
-
tiles: tiles,
|
|
2565
|
-
spatialFilter,
|
|
2566
|
-
spatialDataColumn,
|
|
2567
|
-
spatialDataType
|
|
2568
|
-
});
|
|
2569
|
-
}
|
|
2570
|
-
return tileFeaturesGeometries({
|
|
2571
|
-
tiles,
|
|
2572
|
-
tileFormat,
|
|
2573
|
-
spatialFilter,
|
|
2574
|
-
uniqueIdProperty,
|
|
2575
|
-
options
|
|
2576
|
-
});
|
|
2577
|
-
}
|
|
2578
|
-
|
|
2579
|
-
/** @internalRemarks Source: @carto/react-core */
|
|
2580
|
-
const aggregationFunctions = {
|
|
2581
|
-
count: values => values.length,
|
|
2582
|
-
min: (...args) => applyAggregationFunction(min, ...args),
|
|
2583
|
-
max: (...args) => applyAggregationFunction(max, ...args),
|
|
2584
|
-
sum: (...args) => applyAggregationFunction(sum, ...args),
|
|
2585
|
-
avg: (...args) => applyAggregationFunction(avg, ...args)
|
|
2586
|
-
};
|
|
2587
|
-
/** @internalRemarks Source: @carto/react-core */
|
|
2588
|
-
function aggregate(feature, keys, operation) {
|
|
2589
|
-
if (!(keys != null && keys.length)) {
|
|
2590
|
-
throw new Error('Cannot aggregate a feature without having keys');
|
|
2591
|
-
} else if (keys.length === 1) {
|
|
2592
|
-
const value = feature[keys[0]];
|
|
2593
|
-
return isPotentiallyValidNumber(value) ? Number(value) : value;
|
|
2594
|
-
}
|
|
2595
|
-
const aggregationFn = aggregationFunctions[operation];
|
|
2596
|
-
if (!aggregationFn) {
|
|
2597
|
-
throw new Error(`${operation} isn't a valid aggregation function`);
|
|
2598
|
-
}
|
|
2599
|
-
return aggregationFn(keys.map(column => {
|
|
2600
|
-
const value = feature[column];
|
|
2601
|
-
return isPotentiallyValidNumber(value) ? Number(value) : value;
|
|
2602
|
-
}));
|
|
2603
|
-
}
|
|
2604
|
-
/*
|
|
2605
|
-
* Forced casting to Number (just of non empty strings) allows to work-around
|
|
2606
|
-
* some specific situations, where a big numeric field is transformed into a string when generating the tileset(eg.PG)
|
|
2607
|
-
*/
|
|
2608
|
-
function isPotentiallyValidNumber(value) {
|
|
2609
|
-
return typeof value === 'string' && value.trim().length > 0;
|
|
2610
|
-
}
|
|
2611
|
-
const applyAggregationFunction = (aggFn, values, keys, operation) => {
|
|
2612
|
-
const normalizedKeys = normalizeKeys(keys);
|
|
2613
|
-
const elements = ((normalizedKeys == null ? void 0 : normalizedKeys.length) || 0) <= 1 ? filterFalsyElements(values, normalizedKeys || []) : values;
|
|
2614
|
-
return aggFn(elements, keys, operation);
|
|
2615
|
-
};
|
|
2616
|
-
function filterFalsyElements(values, keys) {
|
|
2617
|
-
const filterFn = value => value !== null && value !== undefined;
|
|
2618
|
-
if (!(keys != null && keys.length)) {
|
|
2619
|
-
return values.filter(filterFn);
|
|
2620
|
-
}
|
|
2621
|
-
return values.filter(v => filterFn(v[keys[0]]));
|
|
2622
|
-
}
|
|
2623
|
-
// Aggregation functions
|
|
2624
|
-
function avg(values, keys, joinOperation) {
|
|
2625
|
-
return sum(values, keys, joinOperation) / (values.length || 1);
|
|
2626
|
-
}
|
|
2627
|
-
function sum(values, keys, joinOperation) {
|
|
2628
|
-
const normalizedKeys = normalizeKeys(keys);
|
|
2629
|
-
if (normalizedKeys) {
|
|
2630
|
-
return values.reduce((a, b) => a + aggregate(b, normalizedKeys, joinOperation), 0);
|
|
2631
|
-
}
|
|
2632
|
-
return values.reduce((a, b) => a + b, 0);
|
|
2633
|
-
}
|
|
2634
|
-
function min(values, keys, joinOperation) {
|
|
2635
|
-
const normalizedKeys = normalizeKeys(keys);
|
|
2636
|
-
if (normalizedKeys) {
|
|
2637
|
-
return values.reduce((a, b) => Math.min(a, aggregate(b, normalizedKeys, joinOperation)), Infinity);
|
|
2638
|
-
}
|
|
2639
|
-
return Math.min(...values);
|
|
2640
|
-
}
|
|
2641
|
-
function max(values, keys, joinOperation) {
|
|
2642
|
-
const normalizedKeys = normalizeKeys(keys);
|
|
2643
|
-
if (normalizedKeys) {
|
|
2644
|
-
return values.reduce((a, b) => Math.max(a, aggregate(b, normalizedKeys, joinOperation)), -Infinity);
|
|
2645
|
-
}
|
|
2646
|
-
return Math.max(...values);
|
|
2647
|
-
}
|
|
2648
|
-
// Aux
|
|
2649
|
-
// Keys can come as a string (one column) or a strings array (multiple column)
|
|
2650
|
-
// Use always an array to make the code easier
|
|
2651
|
-
function normalizeKeys(keys) {
|
|
2652
|
-
return Array.isArray(keys) ? keys : typeof keys === 'string' ? [keys] : undefined;
|
|
2653
|
-
}
|
|
2654
|
-
|
|
2655
|
-
/***
|
|
2656
|
-
Copyright 2013 Teun Duynstee
|
|
2657
|
-
|
|
2658
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
2659
|
-
you may not use this file except in compliance with the License.
|
|
2660
|
-
You may obtain a copy of the License at
|
|
2661
|
-
|
|
2662
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
2663
|
-
|
|
2664
|
-
Unless required by applicable law or agreed to in writing, software
|
|
2665
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
2666
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
2667
|
-
See the License for the specific language governing permissions and
|
|
2668
|
-
limitations under the License.
|
|
2669
|
-
*/
|
|
2670
|
-
var thenBy_module = function () {
|
|
2671
|
-
function identity(v) {
|
|
2672
|
-
return v;
|
|
2673
|
-
}
|
|
2674
|
-
function ignoreCase(v) {
|
|
2675
|
-
return typeof v === "string" ? v.toLowerCase() : v;
|
|
2676
|
-
}
|
|
2677
|
-
function makeCompareFunction(f, opt) {
|
|
2678
|
-
opt = typeof opt === "object" ? opt : {
|
|
2679
|
-
direction: opt
|
|
2680
|
-
};
|
|
2681
|
-
if (typeof f != "function") {
|
|
2682
|
-
var prop = f;
|
|
2683
|
-
// make unary function
|
|
2684
|
-
f = function (v1) {
|
|
2685
|
-
return !!v1[prop] ? v1[prop] : "";
|
|
2686
|
-
};
|
|
2687
|
-
}
|
|
2688
|
-
if (f.length === 1) {
|
|
2689
|
-
// f is a unary function mapping a single item to its sort score
|
|
2690
|
-
var uf = f;
|
|
2691
|
-
var preprocess = opt.ignoreCase ? ignoreCase : identity;
|
|
2692
|
-
var cmp = opt.cmp || function (v1, v2) {
|
|
2693
|
-
return v1 < v2 ? -1 : v1 > v2 ? 1 : 0;
|
|
2694
|
-
};
|
|
2695
|
-
f = function (v1, v2) {
|
|
2696
|
-
return cmp(preprocess(uf(v1)), preprocess(uf(v2)));
|
|
2697
|
-
};
|
|
2698
|
-
}
|
|
2699
|
-
const descTokens = {
|
|
2700
|
-
"-1": '',
|
|
2701
|
-
desc: ''
|
|
2702
|
-
};
|
|
2703
|
-
if (opt.direction in descTokens) return function (v1, v2) {
|
|
2704
|
-
return -f(v1, v2);
|
|
2705
|
-
};
|
|
2706
|
-
return f;
|
|
2707
|
-
}
|
|
2708
|
-
|
|
2709
|
-
/* adds a secondary compare function to the target function (`this` context)
|
|
2710
|
-
which is applied in case the first one returns 0 (equal)
|
|
2711
|
-
returns a new compare function, which has a `thenBy` method as well */
|
|
2712
|
-
function tb(func, opt) {
|
|
2713
|
-
/* should get value false for the first call. This can be done by calling the
|
|
2714
|
-
exported function, or the firstBy property on it (for es6 module compatibility)
|
|
2715
|
-
*/
|
|
2716
|
-
var x = typeof this == "function" && !this.firstBy ? this : false;
|
|
2717
|
-
var y = makeCompareFunction(func, opt);
|
|
2718
|
-
var f = x ? function (a, b) {
|
|
2719
|
-
return x(a, b) || y(a, b);
|
|
2720
|
-
} : y;
|
|
2721
|
-
f.thenBy = tb;
|
|
2722
|
-
return f;
|
|
2723
|
-
}
|
|
2724
|
-
tb.firstBy = tb;
|
|
2725
|
-
return tb;
|
|
2726
|
-
}();
|
|
2727
|
-
|
|
2728
|
-
/**
|
|
2729
|
-
* Apply sort structure to a collection of features
|
|
2730
|
-
* @param features
|
|
2731
|
-
* @param [sortOptions]
|
|
2732
|
-
* @param [sortOptions.sortBy] - One or more columns to sort by
|
|
2733
|
-
* @param [sortOptions.sortByDirection] - Direction by the columns will be sorted
|
|
2734
|
-
* @param [sortOptions.sortByColumnType] - Column type
|
|
2735
|
-
* @internal
|
|
2736
|
-
* @internalRemarks Source: @carto/react-core
|
|
2737
|
-
*/
|
|
2738
|
-
function applySorting(features, {
|
|
2739
|
-
sortBy,
|
|
2740
|
-
sortByDirection = 'asc',
|
|
2741
|
-
sortByColumnType = 'string'
|
|
2742
|
-
} = {}) {
|
|
2743
|
-
// If sortBy is undefined, pass all features
|
|
2744
|
-
if (sortBy === undefined) {
|
|
2745
|
-
return features;
|
|
2746
|
-
}
|
|
2747
|
-
// sortOptions exists, but are bad formatted
|
|
2748
|
-
const isValidSortBy = Array.isArray(sortBy) && sortBy.length ||
|
|
2749
|
-
// sortBy can be an array of columns
|
|
2750
|
-
typeof sortBy === 'string'; // or just one column
|
|
2751
|
-
if (!isValidSortBy) {
|
|
2752
|
-
throw new Error('Sorting options are bad formatted');
|
|
2753
|
-
}
|
|
2754
|
-
const sortFn = createSortFn({
|
|
2755
|
-
sortBy,
|
|
2756
|
-
sortByDirection,
|
|
2757
|
-
sortByColumnType: sortByColumnType || 'string'
|
|
2758
|
-
});
|
|
2759
|
-
return features.sort(sortFn);
|
|
2760
|
-
}
|
|
2761
|
-
// Aux
|
|
2762
|
-
function createSortFn({
|
|
2763
|
-
sortBy,
|
|
2764
|
-
sortByDirection,
|
|
2765
|
-
sortByColumnType
|
|
2766
|
-
}) {
|
|
2767
|
-
const [firstSortOption, ...othersSortOptions] = normalizeSortByOptions({
|
|
2768
|
-
sortBy,
|
|
2769
|
-
sortByDirection,
|
|
2770
|
-
sortByColumnType
|
|
2771
|
-
});
|
|
2772
|
-
let sortFn = thenBy_module.firstBy(...firstSortOption);
|
|
2773
|
-
for (let sortOptions of othersSortOptions) {
|
|
2774
|
-
sortFn = sortFn.thenBy(...sortOptions);
|
|
2775
|
-
}
|
|
2776
|
-
return sortFn;
|
|
2777
|
-
}
|
|
2778
|
-
function normalizeSortByOptions({
|
|
2779
|
-
sortBy,
|
|
2780
|
-
sortByDirection,
|
|
2781
|
-
sortByColumnType
|
|
2782
|
-
}) {
|
|
2783
|
-
const numberFormat = sortByColumnType === 'number' && {
|
|
2784
|
-
cmp: (a, b) => a - b
|
|
2785
|
-
};
|
|
2786
|
-
if (!Array.isArray(sortBy)) {
|
|
2787
|
-
sortBy = [sortBy];
|
|
2788
|
-
}
|
|
2789
|
-
return sortBy.map(sortByEl => {
|
|
2790
|
-
// sortByEl is 'column'
|
|
2791
|
-
if (typeof sortByEl === 'string') {
|
|
2792
|
-
return [sortByEl, _extends({
|
|
2793
|
-
direction: sortByDirection
|
|
2794
|
-
}, numberFormat)];
|
|
2795
|
-
}
|
|
2796
|
-
if (Array.isArray(sortByEl)) {
|
|
2797
|
-
// sortBy is ['column']
|
|
2798
|
-
if (sortByEl[1] === undefined) {
|
|
2799
|
-
return [sortByEl, _extends({
|
|
2800
|
-
direction: sortByDirection
|
|
2801
|
-
}, numberFormat)];
|
|
2802
|
-
}
|
|
2803
|
-
// sortBy is ['column', { ... }]
|
|
2804
|
-
if (typeof sortByEl[1] === 'object') {
|
|
2805
|
-
const othersSortOptions = numberFormat ? _extends({}, numberFormat, sortByEl[1]) : sortByEl[1];
|
|
2806
|
-
return [sortByEl[0], _extends({
|
|
2807
|
-
direction: sortByDirection
|
|
2808
|
-
}, othersSortOptions)];
|
|
2809
|
-
}
|
|
2810
|
-
}
|
|
2811
|
-
return sortByEl;
|
|
2812
|
-
});
|
|
2813
|
-
}
|
|
2814
|
-
|
|
2815
|
-
/** @internalRemarks Source: @carto/react-core */
|
|
2816
|
-
function groupValuesByColumn({
|
|
2817
|
-
data,
|
|
2818
|
-
valuesColumns,
|
|
2819
|
-
joinOperation,
|
|
2820
|
-
keysColumn,
|
|
2821
|
-
operation
|
|
2822
|
-
}) {
|
|
2823
|
-
if (Array.isArray(data) && data.length === 0) {
|
|
2824
|
-
return null;
|
|
2825
|
-
}
|
|
2826
|
-
const groups = data.reduce((accumulator, item) => {
|
|
2827
|
-
const group = item[keysColumn];
|
|
2828
|
-
const values = accumulator.get(group) || [];
|
|
2829
|
-
accumulator.set(group, values);
|
|
2830
|
-
const aggregatedValue = aggregate(item, valuesColumns, joinOperation);
|
|
2831
|
-
const isValid = (operation === 'count' ? true : aggregatedValue !== null) && aggregatedValue !== undefined;
|
|
2832
|
-
if (isValid) {
|
|
2833
|
-
values.push(aggregatedValue);
|
|
2834
|
-
accumulator.set(group, values);
|
|
2835
|
-
}
|
|
2836
|
-
return accumulator;
|
|
2837
|
-
}, new Map()); // We use a map to be able to maintain the type in the key value
|
|
2838
|
-
const targetOperation = aggregationFunctions[operation];
|
|
2839
|
-
if (targetOperation) {
|
|
2840
|
-
return Array.from(groups).map(([name, value]) => ({
|
|
2841
|
-
name,
|
|
2842
|
-
value: targetOperation(value)
|
|
2843
|
-
}));
|
|
2844
|
-
}
|
|
2845
|
-
return [];
|
|
2846
|
-
}
|
|
2847
|
-
|
|
2848
|
-
/**
|
|
2849
|
-
* Returns midnight (local time) on the Monday preceeding a given date, in
|
|
2850
|
-
* milliseconds since the UNIX epoch.
|
|
2851
|
-
*/
|
|
2852
|
-
/**
|
|
2853
|
-
* Returns midnight (UTC) on the Monday preceeding a given date, in
|
|
2854
|
-
* milliseconds since the UNIX epoch.
|
|
2855
|
-
*/
|
|
2856
|
-
function getUTCMonday(date) {
|
|
2857
|
-
const dateCp = new Date(date);
|
|
2858
|
-
const day = dateCp.getUTCDay();
|
|
2859
|
-
const diff = dateCp.getUTCDate() - day + (day ? 1 : -6); // adjust when day is sunday
|
|
2860
|
-
dateCp.setUTCDate(diff);
|
|
2861
|
-
return Date.UTC(dateCp.getUTCFullYear(), dateCp.getUTCMonth(), dateCp.getUTCDate());
|
|
2862
|
-
}
|
|
2863
|
-
|
|
2864
|
-
const GROUP_KEY_FN_MAPPING = {
|
|
2865
|
-
year: date => Date.UTC(date.getUTCFullYear()),
|
|
2866
|
-
month: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth()),
|
|
2867
|
-
week: date => getUTCMonday(date),
|
|
2868
|
-
day: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()),
|
|
2869
|
-
hour: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours()),
|
|
2870
|
-
minute: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes()),
|
|
2871
|
-
second: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds())
|
|
2872
|
-
};
|
|
2873
|
-
/** @internalRemarks Source: @carto/react-core */
|
|
2874
|
-
function groupValuesByDateColumn({
|
|
2875
|
-
data,
|
|
2876
|
-
valuesColumns,
|
|
2877
|
-
joinOperation,
|
|
2878
|
-
keysColumn,
|
|
2879
|
-
groupType,
|
|
2880
|
-
operation
|
|
2881
|
-
}) {
|
|
2882
|
-
if (Array.isArray(data) && data.length === 0) {
|
|
2883
|
-
return null;
|
|
2884
|
-
}
|
|
2885
|
-
const groupKeyFn = GROUP_KEY_FN_MAPPING[groupType];
|
|
2886
|
-
if (!groupKeyFn) {
|
|
2887
|
-
return null;
|
|
2888
|
-
}
|
|
2889
|
-
const groups = data.reduce((acc, item) => {
|
|
2890
|
-
const value = item[keysColumn];
|
|
2891
|
-
const formattedValue = new Date(value);
|
|
2892
|
-
const groupKey = groupKeyFn(formattedValue);
|
|
2893
|
-
if (!isNaN(groupKey)) {
|
|
2894
|
-
let groupedValues = acc.get(groupKey);
|
|
2895
|
-
if (!groupedValues) {
|
|
2896
|
-
groupedValues = [];
|
|
2897
|
-
acc.set(groupKey, groupedValues);
|
|
2898
|
-
}
|
|
2899
|
-
const aggregatedValue = aggregate(item, valuesColumns, joinOperation);
|
|
2900
|
-
const isValid = aggregatedValue !== null && aggregatedValue !== undefined;
|
|
2901
|
-
if (isValid) {
|
|
2902
|
-
groupedValues.push(aggregatedValue);
|
|
2903
|
-
acc.set(groupKey, groupedValues);
|
|
2904
|
-
}
|
|
2905
|
-
}
|
|
2906
|
-
return acc;
|
|
2907
|
-
}, new Map());
|
|
2908
|
-
const targetOperation = aggregationFunctions[operation];
|
|
2909
|
-
return [...groups.entries()].map(([name, value]) => ({
|
|
2910
|
-
name,
|
|
2911
|
-
value: targetOperation(value)
|
|
2912
|
-
})).sort((a, b) => a.name - b.name);
|
|
2913
|
-
}
|
|
2914
|
-
|
|
2915
|
-
/**
|
|
2916
|
-
* Histogram computation.
|
|
2917
|
-
* @internalRemarks Source: @carto/react-core
|
|
2918
|
-
*/
|
|
2919
|
-
function histogram({
|
|
2920
|
-
data,
|
|
2921
|
-
valuesColumns,
|
|
2922
|
-
joinOperation,
|
|
2923
|
-
ticks,
|
|
2924
|
-
operation
|
|
2925
|
-
}) {
|
|
2926
|
-
if (Array.isArray(data) && data.length === 0) {
|
|
2927
|
-
return [];
|
|
2928
|
-
}
|
|
2929
|
-
const binsContainer = [Number.MIN_SAFE_INTEGER, ...ticks].map((tick, index, arr) => ({
|
|
2930
|
-
bin: index,
|
|
2931
|
-
start: tick,
|
|
2932
|
-
end: index === arr.length - 1 ? Number.MAX_SAFE_INTEGER : arr[index + 1],
|
|
2933
|
-
values: []
|
|
2934
|
-
}));
|
|
2935
|
-
data.forEach(feature => {
|
|
2936
|
-
const featureValue = aggregate(feature, valuesColumns, joinOperation);
|
|
2937
|
-
const isValid = featureValue !== null && featureValue !== undefined;
|
|
2938
|
-
if (!isValid) {
|
|
2939
|
-
return;
|
|
2940
|
-
}
|
|
2941
|
-
const binContainer = binsContainer.find(bin => bin.start <= featureValue && bin.end > featureValue);
|
|
2942
|
-
if (!binContainer) {
|
|
2943
|
-
return;
|
|
2944
|
-
}
|
|
2945
|
-
binContainer.values.push(featureValue);
|
|
2946
|
-
});
|
|
2947
|
-
const targetOperation = aggregationFunctions[operation];
|
|
2948
|
-
const transformedBins = binsContainer.map(binContainer => binContainer.values);
|
|
2949
|
-
return transformedBins.map(values => values.length ? targetOperation(values) : 0);
|
|
2950
|
-
}
|
|
2951
|
-
|
|
2952
|
-
/**
|
|
2953
|
-
* Filters invalid features and formats data.
|
|
2954
|
-
* @internalRemarks Source: @carto/react-core
|
|
2955
|
-
*/
|
|
2956
|
-
function scatterPlot({
|
|
2957
|
-
data,
|
|
2958
|
-
xAxisColumns,
|
|
2959
|
-
xAxisJoinOperation,
|
|
2960
|
-
yAxisColumns,
|
|
2961
|
-
yAxisJoinOperation
|
|
2962
|
-
}) {
|
|
2963
|
-
return data.reduce((acc, feature) => {
|
|
2964
|
-
const xValue = aggregate(feature, xAxisColumns, xAxisJoinOperation);
|
|
2965
|
-
const xIsValid = xValue !== null && xValue !== undefined;
|
|
2966
|
-
const yValue = aggregate(feature, yAxisColumns, yAxisJoinOperation);
|
|
2967
|
-
const yIsValid = yValue !== null && yValue !== undefined;
|
|
2968
|
-
if (xIsValid && yIsValid) {
|
|
2969
|
-
acc.push([xValue, yValue]);
|
|
2970
|
-
}
|
|
2971
|
-
return acc;
|
|
2972
|
-
}, []);
|
|
2973
|
-
}
|
|
2974
|
-
|
|
2975
|
-
const _excluded = ["filterOwner", "spatialFilter", "abortController"];
|
|
2976
|
-
/**
|
|
2977
|
-
* Source for Widget API requests on a data source defined by a tileset.
|
|
2978
|
-
*
|
|
2979
|
-
* Generally not intended to be constructed directly. Instead, call
|
|
2980
|
-
* {@link vectorTilesetSource}, {@link h3TilesetSource}, or {@link quadbinTilesetSource},
|
|
2981
|
-
* which can be shared with map layers. Sources contain a `widgetSource`
|
|
2982
|
-
* property, for use by widget implementations.
|
|
2983
|
-
*
|
|
2984
|
-
* Example:
|
|
2985
|
-
*
|
|
2986
|
-
* ```javascript
|
|
2987
|
-
* import { vectorTilesetSource } from '@carto/api-client';
|
|
2988
|
-
*
|
|
2989
|
-
* const data = vectorTilesetSource({
|
|
2990
|
-
* accessToken: '••••',
|
|
2991
|
-
* connectionName: 'carto_dw',
|
|
2992
|
-
* tableName: 'carto-demo-data.demo_rasters.my_tileset_source'
|
|
2993
|
-
* });
|
|
2994
|
-
*
|
|
2995
|
-
* const { widgetSource } = await data;
|
|
2996
|
-
* ```
|
|
2997
|
-
*/
|
|
2998
|
-
class WidgetTilesetSource extends WidgetSource {
|
|
2999
|
-
constructor(...args) {
|
|
3000
|
-
super(...args);
|
|
3001
|
-
this._tiles = [];
|
|
3002
|
-
this._features = [];
|
|
3003
|
-
}
|
|
3004
|
-
getModelSource(owner) {
|
|
3005
|
-
return _extends({}, super._getModelSource(owner), {
|
|
3006
|
-
type: 'tileset',
|
|
3007
|
-
data: this.props.tableName
|
|
3008
|
-
});
|
|
3009
|
-
}
|
|
3010
|
-
/**
|
|
3011
|
-
* Loads features as a list of tiles (typically provided by deck.gl).
|
|
3012
|
-
* After tiles are loaded, {@link extractTileFeatures} must be called
|
|
3013
|
-
* before computing statistics on the tiles.
|
|
3014
|
-
*/
|
|
3015
|
-
loadTiles(tiles) {
|
|
3016
|
-
this._tiles = tiles;
|
|
3017
|
-
}
|
|
3018
|
-
/**
|
|
3019
|
-
* Extracts feature data from tiles previously loaded with {@link loadTiles}.
|
|
3020
|
-
* Must be called before computing statistics on tiles.
|
|
3021
|
-
*/
|
|
3022
|
-
extractTileFeatures({
|
|
3023
|
-
spatialFilter,
|
|
3024
|
-
uniqueIdProperty,
|
|
3025
|
-
options
|
|
3026
|
-
}) {
|
|
3027
|
-
this._features = tileFeatures({
|
|
3028
|
-
tiles: this._tiles,
|
|
3029
|
-
options,
|
|
3030
|
-
spatialFilter,
|
|
3031
|
-
uniqueIdProperty,
|
|
3032
|
-
tileFormat: this.props.tileFormat,
|
|
3033
|
-
spatialDataColumn: this.props.spatialDataColumn,
|
|
3034
|
-
spatialDataType: this.props.spatialDataType
|
|
3035
|
-
});
|
|
3036
|
-
}
|
|
3037
|
-
/** Loads features as GeoJSON (used for testing). */
|
|
3038
|
-
loadGeoJSON({
|
|
3039
|
-
geojson,
|
|
3040
|
-
spatialFilter,
|
|
3041
|
-
uniqueIdProperty
|
|
3042
|
-
}) {
|
|
3043
|
-
this._features = geojsonFeatures({
|
|
3044
|
-
geojson,
|
|
3045
|
-
spatialFilter,
|
|
3046
|
-
uniqueIdProperty
|
|
3047
|
-
});
|
|
3048
|
-
}
|
|
3049
|
-
async getFeatures(options) {
|
|
3050
|
-
throw new Error('getFeatures not supported for tilesets');
|
|
3051
|
-
}
|
|
3052
|
-
async getFormula({
|
|
3053
|
-
column = '*',
|
|
3054
|
-
operation = 'count',
|
|
3055
|
-
joinOperation,
|
|
3056
|
-
filterOwner
|
|
3057
|
-
}) {
|
|
3058
|
-
if (operation === 'custom') {
|
|
3059
|
-
throw new Error('Custom aggregation not supported for tilesets');
|
|
3060
|
-
}
|
|
3061
|
-
if (!this._features.length) {
|
|
3062
|
-
return {
|
|
3063
|
-
value: null
|
|
3064
|
-
};
|
|
3065
|
-
}
|
|
3066
|
-
// Column is required except when operation is 'count'.
|
|
3067
|
-
if (column && column !== '*' || operation !== 'count') {
|
|
3068
|
-
assertColumn(this._features, column);
|
|
3069
|
-
}
|
|
3070
|
-
const filteredFeatures = this._getFilteredFeatures(filterOwner);
|
|
3071
|
-
if (filteredFeatures.length === 0 && operation !== 'count') {
|
|
3072
|
-
return {
|
|
3073
|
-
value: null
|
|
3074
|
-
};
|
|
3075
|
-
}
|
|
3076
|
-
const targetOperation = aggregationFunctions[operation];
|
|
3077
|
-
return {
|
|
3078
|
-
value: targetOperation(filteredFeatures, column, joinOperation)
|
|
3079
|
-
};
|
|
3080
|
-
}
|
|
3081
|
-
async getHistogram({
|
|
3082
|
-
operation = 'count',
|
|
3083
|
-
ticks,
|
|
3084
|
-
column,
|
|
3085
|
-
joinOperation,
|
|
3086
|
-
filterOwner
|
|
3087
|
-
}) {
|
|
3088
|
-
if (!this._features.length) {
|
|
3089
|
-
return [];
|
|
3090
|
-
}
|
|
3091
|
-
const filteredFeatures = this._getFilteredFeatures(filterOwner);
|
|
3092
|
-
assertColumn(this._features, column);
|
|
3093
|
-
return histogram({
|
|
3094
|
-
data: filteredFeatures,
|
|
3095
|
-
valuesColumns: normalizeColumns(column),
|
|
3096
|
-
joinOperation,
|
|
3097
|
-
ticks,
|
|
3098
|
-
operation
|
|
3099
|
-
});
|
|
3100
|
-
}
|
|
3101
|
-
async getCategories({
|
|
3102
|
-
column,
|
|
3103
|
-
operation = 'count',
|
|
3104
|
-
operationColumn,
|
|
3105
|
-
joinOperation,
|
|
3106
|
-
filterOwner
|
|
3107
|
-
}) {
|
|
3108
|
-
if (!this._features.length) {
|
|
3109
|
-
return [];
|
|
3110
|
-
}
|
|
3111
|
-
const filteredFeatures = this._getFilteredFeatures(filterOwner);
|
|
3112
|
-
assertColumn(this._features, column, operationColumn);
|
|
3113
|
-
const groups = groupValuesByColumn({
|
|
3114
|
-
data: filteredFeatures,
|
|
3115
|
-
valuesColumns: normalizeColumns(operationColumn || column),
|
|
3116
|
-
joinOperation,
|
|
3117
|
-
keysColumn: column,
|
|
3118
|
-
operation
|
|
3119
|
-
});
|
|
3120
|
-
return groups || [];
|
|
3121
|
-
}
|
|
3122
|
-
async getScatter({
|
|
3123
|
-
xAxisColumn,
|
|
3124
|
-
yAxisColumn,
|
|
3125
|
-
xAxisJoinOperation,
|
|
3126
|
-
yAxisJoinOperation,
|
|
3127
|
-
filterOwner
|
|
3128
|
-
}) {
|
|
3129
|
-
if (!this._features.length) {
|
|
3130
|
-
return [];
|
|
3131
|
-
}
|
|
3132
|
-
const filteredFeatures = this._getFilteredFeatures(filterOwner);
|
|
3133
|
-
assertColumn(this._features, xAxisColumn, yAxisColumn);
|
|
3134
|
-
return scatterPlot({
|
|
3135
|
-
data: filteredFeatures,
|
|
3136
|
-
xAxisColumns: normalizeColumns(xAxisColumn),
|
|
3137
|
-
xAxisJoinOperation,
|
|
3138
|
-
yAxisColumns: normalizeColumns(yAxisColumn),
|
|
3139
|
-
yAxisJoinOperation
|
|
3140
|
-
});
|
|
3141
|
-
}
|
|
3142
|
-
async getTable(options) {
|
|
3143
|
-
const {
|
|
3144
|
-
filterOwner
|
|
3145
|
-
} = options,
|
|
3146
|
-
params = _objectWithoutPropertiesLoose(options, _excluded);
|
|
3147
|
-
const {
|
|
3148
|
-
columns,
|
|
3149
|
-
searchFilterColumn,
|
|
3150
|
-
searchFilterText,
|
|
3151
|
-
sortBy,
|
|
3152
|
-
sortDirection,
|
|
3153
|
-
sortByColumnType,
|
|
3154
|
-
offset = 0,
|
|
3155
|
-
limit = 10
|
|
3156
|
-
} = params;
|
|
3157
|
-
if (!this._features.length) {
|
|
3158
|
-
return {
|
|
3159
|
-
rows: [],
|
|
3160
|
-
totalCount: 0
|
|
3161
|
-
};
|
|
3162
|
-
}
|
|
3163
|
-
// Filter.
|
|
3164
|
-
let filteredFeatures = this._getFilteredFeatures(filterOwner);
|
|
3165
|
-
// Search.
|
|
3166
|
-
// TODO: Could we get the same behavior by applying filters in loadTiles()?
|
|
3167
|
-
if (searchFilterColumn && searchFilterText) {
|
|
3168
|
-
filteredFeatures = filteredFeatures.filter(row => row[searchFilterColumn] && String(row[searchFilterColumn]).toLowerCase().includes(String(searchFilterText).toLowerCase()));
|
|
3169
|
-
}
|
|
3170
|
-
// Sort.
|
|
3171
|
-
let rows = applySorting(filteredFeatures, {
|
|
3172
|
-
sortBy,
|
|
3173
|
-
sortByDirection: sortDirection,
|
|
3174
|
-
sortByColumnType
|
|
3175
|
-
});
|
|
3176
|
-
const totalCount = rows.length;
|
|
3177
|
-
// Offset and limit.
|
|
3178
|
-
rows = rows.slice(Math.min(offset, totalCount), Math.min(offset + limit, totalCount));
|
|
3179
|
-
// Select columns.
|
|
3180
|
-
rows = rows.map(srcRow => {
|
|
3181
|
-
const dstRow = {};
|
|
3182
|
-
for (const column of columns) {
|
|
3183
|
-
dstRow[column] = srcRow[column];
|
|
3184
|
-
}
|
|
3185
|
-
return dstRow;
|
|
3186
|
-
});
|
|
3187
|
-
return {
|
|
3188
|
-
rows,
|
|
3189
|
-
totalCount
|
|
3190
|
-
};
|
|
3191
|
-
}
|
|
3192
|
-
async getTimeSeries({
|
|
3193
|
-
column,
|
|
3194
|
-
stepSize,
|
|
3195
|
-
operation,
|
|
3196
|
-
operationColumn,
|
|
3197
|
-
joinOperation,
|
|
3198
|
-
filterOwner
|
|
3199
|
-
}) {
|
|
3200
|
-
if (!this._features.length) {
|
|
3201
|
-
return {
|
|
3202
|
-
rows: []
|
|
3203
|
-
};
|
|
3204
|
-
}
|
|
3205
|
-
const filteredFeatures = this._getFilteredFeatures(filterOwner);
|
|
3206
|
-
assertColumn(this._features, column, operationColumn);
|
|
3207
|
-
const rows = groupValuesByDateColumn({
|
|
3208
|
-
data: filteredFeatures,
|
|
3209
|
-
valuesColumns: normalizeColumns(operationColumn || column),
|
|
3210
|
-
keysColumn: column,
|
|
3211
|
-
groupType: stepSize,
|
|
3212
|
-
operation,
|
|
3213
|
-
joinOperation
|
|
3214
|
-
}) || [];
|
|
3215
|
-
return {
|
|
3216
|
-
rows
|
|
3217
|
-
};
|
|
3218
|
-
}
|
|
3219
|
-
async getRange({
|
|
3220
|
-
column,
|
|
3221
|
-
filterOwner
|
|
3222
|
-
}) {
|
|
3223
|
-
if (!this._features.length) {
|
|
3224
|
-
// TODO: Is this the only nullable response in the Widgets API? If so,
|
|
3225
|
-
// can we do something more consistent?
|
|
3226
|
-
return null;
|
|
3227
|
-
}
|
|
3228
|
-
assertColumn(this._features, column);
|
|
3229
|
-
const filteredFeatures = this._getFilteredFeatures(filterOwner);
|
|
3230
|
-
return {
|
|
3231
|
-
min: aggregationFunctions.min(filteredFeatures, column),
|
|
3232
|
-
max: aggregationFunctions.max(filteredFeatures, column)
|
|
3233
|
-
};
|
|
3234
|
-
}
|
|
3235
|
-
/****************************************************************************
|
|
3236
|
-
* INTERNAL
|
|
3237
|
-
*/
|
|
3238
|
-
_getFilteredFeatures(filterOwner) {
|
|
3239
|
-
return applyFilters(this._features, getApplicableFilters(filterOwner, this.props.filters), this.props.filtersLogicalOperator || 'and');
|
|
3240
|
-
}
|
|
3241
|
-
}
|
|
3242
|
-
function assertColumn(features, ...columnArgs) {
|
|
3243
|
-
// TODO(cleanup): Can drop support for multiple column shapes here?
|
|
3244
|
-
// Due to the multiple column shape, we normalise it as an array with normalizeColumns
|
|
3245
|
-
const columns = Array.from(new Set(columnArgs.map(normalizeColumns).flat()));
|
|
3246
|
-
const featureKeys = Object.keys(features[0]);
|
|
3247
|
-
const invalidColumns = columns.filter(column => !featureKeys.includes(column));
|
|
3248
|
-
if (invalidColumns.length) {
|
|
3249
|
-
throw new InvalidColumnError(`Missing column(s): ${invalidColumns.join(', ')}`);
|
|
3250
|
-
}
|
|
3251
|
-
}
|
|
3252
|
-
function normalizeColumns(columns) {
|
|
3253
|
-
return Array.isArray(columns) ? columns : typeof columns === 'string' ? [columns] : [];
|
|
3254
|
-
}
|
|
3255
|
-
|
|
3256
|
-
const h3QuerySource = async function h3QuerySource(options) {
|
|
3257
|
-
const {
|
|
3258
|
-
aggregationExp,
|
|
3259
|
-
aggregationResLevel = DEFAULT_AGGREGATION_RES_LEVEL_H3,
|
|
3260
|
-
sqlQuery,
|
|
3261
|
-
spatialDataColumn = 'h3',
|
|
3262
|
-
queryParameters,
|
|
3263
|
-
filters
|
|
3264
|
-
} = options;
|
|
3265
|
-
const spatialDataType = 'h3';
|
|
3266
|
-
const urlParameters = {
|
|
3267
|
-
aggregationExp,
|
|
3268
|
-
spatialDataColumn,
|
|
3269
|
-
spatialDataType,
|
|
3270
|
-
q: sqlQuery
|
|
3271
|
-
};
|
|
3272
|
-
if (aggregationResLevel) {
|
|
3273
|
-
urlParameters.aggregationResLevel = String(aggregationResLevel);
|
|
3274
|
-
}
|
|
3275
|
-
if (queryParameters) {
|
|
3276
|
-
urlParameters.queryParameters = queryParameters;
|
|
3277
|
-
}
|
|
3278
|
-
if (filters) {
|
|
3279
|
-
urlParameters.filters = filters;
|
|
3280
|
-
}
|
|
3281
|
-
return baseSource('query', options, urlParameters).then(result => _extends({}, result, {
|
|
3282
|
-
widgetSource: new WidgetQuerySource(_extends({}, options, {
|
|
3283
|
-
// NOTE: Parameters with default values above must be explicitly passed here.
|
|
3284
|
-
spatialDataColumn,
|
|
3285
|
-
spatialDataType
|
|
3286
|
-
}))
|
|
3287
|
-
}));
|
|
3288
|
-
};
|
|
3289
|
-
|
|
3290
|
-
const h3TableSource = async function h3TableSource(options) {
|
|
3291
|
-
const {
|
|
3292
|
-
aggregationExp,
|
|
3293
|
-
aggregationResLevel = DEFAULT_AGGREGATION_RES_LEVEL_H3,
|
|
3294
|
-
spatialDataColumn = 'h3',
|
|
3295
|
-
tableName,
|
|
3296
|
-
filters
|
|
3297
|
-
} = options;
|
|
3298
|
-
const spatialDataType = 'h3';
|
|
3299
|
-
const urlParameters = {
|
|
3300
|
-
aggregationExp,
|
|
3301
|
-
name: tableName,
|
|
3302
|
-
spatialDataColumn,
|
|
3303
|
-
spatialDataType
|
|
3304
|
-
};
|
|
3305
|
-
if (aggregationResLevel) {
|
|
3306
|
-
urlParameters.aggregationResLevel = String(aggregationResLevel);
|
|
3307
|
-
}
|
|
3308
|
-
if (filters) {
|
|
3309
|
-
urlParameters.filters = filters;
|
|
3310
|
-
}
|
|
3311
|
-
return baseSource('table', options, urlParameters).then(result => _extends({}, result, {
|
|
3312
|
-
widgetSource: new WidgetTableSource(_extends({}, options, {
|
|
3313
|
-
// NOTE: Parameters with default values above must be explicitly passed here.
|
|
3314
|
-
spatialDataColumn,
|
|
3315
|
-
spatialDataType
|
|
3316
|
-
}))
|
|
3317
|
-
}));
|
|
3318
|
-
};
|
|
3319
|
-
|
|
3320
|
-
function getTileFormat(tilejson) {
|
|
3321
|
-
const tileParams = new URL(tilejson.tiles[0]).searchParams;
|
|
3322
|
-
return tileParams.get('formatTiles') === 'mvt' ? TileFormat.MVT : TileFormat.BINARY;
|
|
3323
|
-
}
|
|
3324
|
-
|
|
3325
|
-
const h3TilesetSource = async function h3TilesetSource(options) {
|
|
3326
|
-
const {
|
|
3327
|
-
tableName,
|
|
3328
|
-
spatialDataColumn = 'h3'
|
|
3329
|
-
} = options;
|
|
3330
|
-
const urlParameters = {
|
|
3331
|
-
name: tableName
|
|
3332
|
-
};
|
|
3333
|
-
return baseSource('tileset', options, urlParameters).then(result => _extends({}, result, {
|
|
3334
|
-
widgetSource: new WidgetTilesetSource(_extends({}, options, {
|
|
3335
|
-
tileFormat: getTileFormat(result),
|
|
3336
|
-
spatialDataColumn,
|
|
3337
|
-
spatialDataType: 'h3'
|
|
3338
|
-
}))
|
|
3339
|
-
}));
|
|
3340
|
-
};
|
|
3341
|
-
|
|
3342
|
-
// deck.gl
|
|
3343
|
-
// SPDX-License-Identifier: MIT
|
|
3344
|
-
// Copyright (c) vis.gl contributors
|
|
3345
|
-
const rasterSource = async function rasterSource(options) {
|
|
3346
|
-
const {
|
|
3347
|
-
tableName,
|
|
3348
|
-
filters
|
|
3349
|
-
} = options;
|
|
3350
|
-
const urlParameters = {
|
|
3351
|
-
name: tableName
|
|
3352
|
-
};
|
|
3353
|
-
if (filters) {
|
|
3354
|
-
urlParameters.filters = filters;
|
|
3355
|
-
}
|
|
3356
|
-
return baseSource('raster', options, urlParameters);
|
|
3357
|
-
};
|
|
3358
|
-
|
|
3359
|
-
const quadbinQuerySource = async function quadbinQuerySource(options) {
|
|
3360
|
-
const {
|
|
3361
|
-
aggregationExp,
|
|
3362
|
-
aggregationResLevel = DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN,
|
|
3363
|
-
sqlQuery,
|
|
3364
|
-
spatialDataColumn = 'quadbin',
|
|
3365
|
-
queryParameters,
|
|
3366
|
-
filters
|
|
3367
|
-
} = options;
|
|
3368
|
-
const spatialDataType = 'quadbin';
|
|
3369
|
-
const urlParameters = {
|
|
3370
|
-
aggregationExp,
|
|
3371
|
-
q: sqlQuery,
|
|
3372
|
-
spatialDataColumn,
|
|
3373
|
-
spatialDataType
|
|
3374
|
-
};
|
|
3375
|
-
if (aggregationResLevel) {
|
|
3376
|
-
urlParameters.aggregationResLevel = String(aggregationResLevel);
|
|
3377
|
-
}
|
|
3378
|
-
if (queryParameters) {
|
|
3379
|
-
urlParameters.queryParameters = queryParameters;
|
|
3380
|
-
}
|
|
3381
|
-
if (filters) {
|
|
3382
|
-
urlParameters.filters = filters;
|
|
3383
|
-
}
|
|
3384
|
-
return baseSource('query', options, urlParameters).then(result => _extends({}, result, {
|
|
3385
|
-
widgetSource: new WidgetQuerySource(_extends({}, options, {
|
|
3386
|
-
// NOTE: Parameters with default values above must be explicitly passed here.
|
|
3387
|
-
spatialDataColumn,
|
|
3388
|
-
spatialDataType
|
|
3389
|
-
}))
|
|
3390
|
-
}));
|
|
3391
|
-
};
|
|
3392
|
-
|
|
3393
|
-
const quadbinTableSource = async function quadbinTableSource(options) {
|
|
3394
|
-
const {
|
|
3395
|
-
aggregationExp,
|
|
3396
|
-
aggregationResLevel = DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN,
|
|
3397
|
-
spatialDataColumn = 'quadbin',
|
|
3398
|
-
tableName,
|
|
3399
|
-
filters
|
|
3400
|
-
} = options;
|
|
3401
|
-
const spatialDataType = 'quadbin';
|
|
3402
|
-
const urlParameters = {
|
|
3403
|
-
aggregationExp,
|
|
3404
|
-
name: tableName,
|
|
3405
|
-
spatialDataColumn,
|
|
3406
|
-
spatialDataType
|
|
3407
|
-
};
|
|
3408
|
-
if (aggregationResLevel) {
|
|
3409
|
-
urlParameters.aggregationResLevel = String(aggregationResLevel);
|
|
3410
|
-
}
|
|
3411
|
-
if (filters) {
|
|
3412
|
-
urlParameters.filters = filters;
|
|
3413
|
-
}
|
|
3414
|
-
return baseSource('table', options, urlParameters).then(result => _extends({}, result, {
|
|
3415
|
-
widgetSource: new WidgetTableSource(_extends({}, options, {
|
|
3416
|
-
// NOTE: Parameters with default values above must be explicitly passed here.
|
|
3417
|
-
spatialDataColumn,
|
|
3418
|
-
spatialDataType
|
|
3419
|
-
}))
|
|
3420
|
-
}));
|
|
3421
|
-
};
|
|
3422
|
-
|
|
3423
|
-
const quadbinTilesetSource = async function quadbinTilesetSource(options) {
|
|
3424
|
-
const {
|
|
3425
|
-
tableName,
|
|
3426
|
-
spatialDataColumn = 'quadbin'
|
|
3427
|
-
} = options;
|
|
3428
|
-
const urlParameters = {
|
|
3429
|
-
name: tableName
|
|
3430
|
-
};
|
|
3431
|
-
return baseSource('tileset', options, urlParameters).then(result => _extends({}, result, {
|
|
3432
|
-
widgetSource: new WidgetTilesetSource(_extends({}, options, {
|
|
3433
|
-
tileFormat: getTileFormat(result),
|
|
3434
|
-
spatialDataColumn,
|
|
3435
|
-
spatialDataType: 'quadbin'
|
|
3436
|
-
}))
|
|
3437
|
-
}));
|
|
3438
|
-
};
|
|
3439
|
-
|
|
3440
|
-
const vectorQuerySource = async function vectorQuerySource(options) {
|
|
3441
|
-
const {
|
|
3442
|
-
columns,
|
|
3443
|
-
filters,
|
|
3444
|
-
spatialDataColumn = DEFAULT_GEO_COLUMN,
|
|
3445
|
-
sqlQuery,
|
|
3446
|
-
tileResolution = DEFAULT_TILE_RESOLUTION,
|
|
3447
|
-
queryParameters,
|
|
3448
|
-
aggregationExp
|
|
3449
|
-
} = options;
|
|
3450
|
-
const spatialDataType = 'geo';
|
|
3451
|
-
const urlParameters = {
|
|
3452
|
-
spatialDataColumn,
|
|
3453
|
-
spatialDataType,
|
|
3454
|
-
tileResolution: tileResolution.toString(),
|
|
3455
|
-
q: sqlQuery
|
|
3456
|
-
};
|
|
3457
|
-
if (columns) {
|
|
3458
|
-
urlParameters.columns = columns.join(',');
|
|
3459
|
-
}
|
|
3460
|
-
if (filters) {
|
|
3461
|
-
urlParameters.filters = filters;
|
|
3462
|
-
}
|
|
3463
|
-
if (queryParameters) {
|
|
3464
|
-
urlParameters.queryParameters = queryParameters;
|
|
3465
|
-
}
|
|
3466
|
-
if (aggregationExp) {
|
|
3467
|
-
urlParameters.aggregationExp = aggregationExp;
|
|
3468
|
-
}
|
|
3469
|
-
return baseSource('query', options, urlParameters).then(result => _extends({}, result, {
|
|
3470
|
-
widgetSource: new WidgetQuerySource(_extends({}, options, {
|
|
3471
|
-
// NOTE: Parameters with default values above must be explicitly passed here.
|
|
3472
|
-
spatialDataColumn,
|
|
3473
|
-
spatialDataType,
|
|
3474
|
-
tileResolution
|
|
3475
|
-
}))
|
|
3476
|
-
}));
|
|
3477
|
-
};
|
|
3478
|
-
|
|
3479
|
-
const vectorTableSource = async function vectorTableSource(options) {
|
|
3480
|
-
const {
|
|
3481
|
-
columns,
|
|
3482
|
-
filters,
|
|
3483
|
-
spatialDataColumn = DEFAULT_GEO_COLUMN,
|
|
3484
|
-
tableName,
|
|
3485
|
-
tileResolution = DEFAULT_TILE_RESOLUTION,
|
|
3486
|
-
aggregationExp
|
|
3487
|
-
} = options;
|
|
3488
|
-
const spatialDataType = 'geo';
|
|
3489
|
-
const urlParameters = {
|
|
3490
|
-
name: tableName,
|
|
3491
|
-
spatialDataColumn,
|
|
3492
|
-
spatialDataType,
|
|
3493
|
-
tileResolution: tileResolution.toString()
|
|
3494
|
-
};
|
|
3495
|
-
if (columns) {
|
|
3496
|
-
urlParameters.columns = columns.join(',');
|
|
3497
|
-
}
|
|
3498
|
-
if (filters) {
|
|
3499
|
-
urlParameters.filters = filters;
|
|
3500
|
-
}
|
|
3501
|
-
if (aggregationExp) {
|
|
3502
|
-
urlParameters.aggregationExp = aggregationExp;
|
|
3503
|
-
}
|
|
3504
|
-
return baseSource('table', options, urlParameters).then(result => _extends({}, result, {
|
|
3505
|
-
widgetSource: new WidgetTableSource(_extends({}, options, {
|
|
3506
|
-
// NOTE: Parameters with default values above must be explicitly passed here.
|
|
3507
|
-
spatialDataColumn,
|
|
3508
|
-
spatialDataType,
|
|
3509
|
-
tileResolution
|
|
3510
|
-
}))
|
|
3511
|
-
}));
|
|
3512
|
-
};
|
|
3513
|
-
|
|
3514
|
-
const vectorTilesetSource = async function vectorTilesetSource(options) {
|
|
3515
|
-
const {
|
|
3516
|
-
tableName,
|
|
3517
|
-
spatialDataColumn = DEFAULT_GEO_COLUMN
|
|
3518
|
-
} = options;
|
|
3519
|
-
const urlParameters = {
|
|
3520
|
-
name: tableName
|
|
3521
|
-
};
|
|
3522
|
-
return baseSource('tileset', options, urlParameters).then(result => _extends({}, result, {
|
|
3523
|
-
widgetSource: new WidgetTilesetSource(_extends({}, options, {
|
|
3524
|
-
tileFormat: getTileFormat(result),
|
|
3525
|
-
spatialDataColumn,
|
|
3526
|
-
spatialDataType: 'geo'
|
|
3527
|
-
}))
|
|
3528
|
-
}));
|
|
3529
|
-
};
|
|
3530
|
-
|
|
3531
|
-
const query = async function query(options) {
|
|
3532
|
-
const {
|
|
3533
|
-
apiBaseUrl = SOURCE_DEFAULTS.apiBaseUrl,
|
|
3534
|
-
clientId = SOURCE_DEFAULTS.clientId,
|
|
3535
|
-
maxLengthURL = SOURCE_DEFAULTS.maxLengthURL,
|
|
3536
|
-
localCache,
|
|
3537
|
-
connectionName,
|
|
3538
|
-
sqlQuery,
|
|
3539
|
-
queryParameters
|
|
3540
|
-
} = options;
|
|
3541
|
-
const urlParameters = {
|
|
3542
|
-
q: sqlQuery
|
|
3543
|
-
};
|
|
3544
|
-
if (queryParameters) {
|
|
3545
|
-
urlParameters.queryParameters = JSON.stringify(queryParameters);
|
|
3546
|
-
}
|
|
3547
|
-
const baseUrl = buildQueryUrl({
|
|
3548
|
-
apiBaseUrl,
|
|
3549
|
-
connectionName
|
|
3550
|
-
});
|
|
3551
|
-
const headers = _extends({
|
|
3552
|
-
Authorization: `Bearer ${options.accessToken}`
|
|
3553
|
-
}, options.headers);
|
|
3554
|
-
const parameters = _extends({
|
|
3555
|
-
client: clientId
|
|
3556
|
-
}, urlParameters);
|
|
3557
|
-
const errorContext = {
|
|
3558
|
-
requestType: 'SQL',
|
|
3559
|
-
connection: options.connectionName,
|
|
3560
|
-
type: 'query',
|
|
3561
|
-
source: JSON.stringify(parameters, undefined, 2)
|
|
3562
|
-
};
|
|
3563
|
-
return await requestWithParameters({
|
|
3564
|
-
baseUrl,
|
|
3565
|
-
parameters,
|
|
3566
|
-
headers,
|
|
3567
|
-
errorContext,
|
|
3568
|
-
maxLengthURL,
|
|
3569
|
-
localCache
|
|
3570
|
-
});
|
|
3571
|
-
};
|
|
3572
|
-
|
|
3573
|
-
export { ApiVersion, CartoAPIError, DEFAULT_API_BASE_URL, FEATURE_GEOM_PROPERTY, FilterType, Provider, SOURCE_DEFAULTS, SpatialIndex, TileFormat, WidgetQuerySource, WidgetRemoteSource, WidgetTableSource, WidgetTilesetSource, addFilter, aggregate, aggregationFunctions, applyFilters, applySorting, boundaryQuerySource, boundaryTableSource, buildBinaryFeatureFilter, buildFeatureFilter, buildPublicMapUrl, buildStatsUrl, clearFilters, createPolygonSpatialFilter, createViewportSpatialFilter, filterFunctions, geojsonFeatures, getClient, getFilter, groupValuesByColumn, groupValuesByDateColumn, h3QuerySource, h3TableSource, h3TilesetSource, hasFilter, histogram, makeIntervalComplete, quadbinQuerySource, quadbinTableSource, quadbinTilesetSource, query, rasterSource, removeFilter, requestWithParameters, scatterPlot, setClient, tileFeatures, tileFeaturesGeometries, tileFeaturesSpatialIndex, transformToTileCoords, vectorQuerySource, vectorTableSource, vectorTilesetSource };
|
|
3574
|
-
//# sourceMappingURL=api-client.modern.js.map
|