@carto/api-client 0.4.7-0 → 0.4.7-alpha.1

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