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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +2910 -2741
  8. package/build/api-client.cjs.map +1 -1
  9. package/build/api-client.modern.js +3718 -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 +74 -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 +40 -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,3718 @@
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
+ WidgetSource.defaultProps = {
2136
+ apiVersion: ApiVersion.V3,
2137
+ apiBaseUrl: DEFAULT_API_BASE_URL,
2138
+ clientId: getClient(),
2139
+ filters: {},
2140
+ filtersLogicalOperator: 'and'
2141
+ };
2142
+
2143
+ /**
2144
+ * Return more descriptive error from API
2145
+ * @privateRemarks Source: @carto/react-api
2146
+ */
2147
+ function dealWithApiError({
2148
+ response,
2149
+ data
2150
+ }) {
2151
+ var _data$error, _data$error2;
2152
+ if (data.error === 'Column not found') {
2153
+ throw new InvalidColumnError(`${data.error} ${data.column_name}`);
2154
+ }
2155
+ if (typeof data.error === 'string' && (_data$error = data.error) != null && _data$error.includes('Missing columns')) {
2156
+ throw new InvalidColumnError(data.error);
2157
+ }
2158
+ switch (response.status) {
2159
+ case 401:
2160
+ throw new Error('Unauthorized access. Invalid credentials');
2161
+ case 403:
2162
+ throw new Error('Forbidden access to the requested data');
2163
+ default:
2164
+ 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])));
2165
+ }
2166
+ }
2167
+ /** @privateRemarks Source: @carto/react-api */
2168
+ async function makeCall({
2169
+ url,
2170
+ accessToken,
2171
+ opts
2172
+ }) {
2173
+ let response;
2174
+ let data;
2175
+ const isPost = (opts == null ? void 0 : opts.method) === 'POST';
2176
+ try {
2177
+ response = await fetch(url.toString(), _extends({
2178
+ headers: _extends({
2179
+ Authorization: `Bearer ${accessToken}`
2180
+ }, isPost && {
2181
+ 'Content-Type': 'application/json'
2182
+ }, opts.headers)
2183
+ }, isPost && {
2184
+ method: opts == null ? void 0 : opts.method,
2185
+ body: opts == null ? void 0 : opts.body
2186
+ }, {
2187
+ signal: opts == null ? void 0 : opts.signal
2188
+ }, opts == null ? void 0 : opts.otherOptions));
2189
+ data = await response.json();
2190
+ } catch (error) {
2191
+ if (error.name === 'AbortError') throw error;
2192
+ throw new Error(`Failed request: ${error}`);
2193
+ }
2194
+ if (!response.ok) {
2195
+ dealWithApiError({
2196
+ response,
2197
+ data
2198
+ });
2199
+ }
2200
+ return data;
2201
+ }
2202
+
2203
+ /** @privateRemarks Source: @carto/react-api */
2204
+ const AVAILABLE_MODELS = ['category', 'histogram', 'formula', 'pick', 'timeseries', 'range', 'scatterplot', 'table'];
2205
+ const {
2206
+ V3
2207
+ } = ApiVersion;
2208
+ const REQUEST_GET_MAX_URL_LENGTH = 2048;
2209
+ /**
2210
+ * Execute a SQL model request.
2211
+ * @privateRemarks Source: @carto/react-api
2212
+ */
2213
+ function executeModel(props) {
2214
+ assert(props.source, 'executeModel: missing source');
2215
+ assert(props.model, 'executeModel: missing model');
2216
+ assert(props.params, 'executeModel: missing params');
2217
+ assert(AVAILABLE_MODELS.includes(props.model), `executeModel: model provided isn't valid. Available models: ${AVAILABLE_MODELS.join(', ')}`);
2218
+ const {
2219
+ model,
2220
+ source,
2221
+ params,
2222
+ opts
2223
+ } = props;
2224
+ const {
2225
+ type,
2226
+ apiVersion,
2227
+ apiBaseUrl,
2228
+ accessToken,
2229
+ connectionName,
2230
+ clientId
2231
+ } = source;
2232
+ assert(apiBaseUrl, 'executeModel: missing apiBaseUrl');
2233
+ assert(accessToken, 'executeModel: missing accessToken');
2234
+ assert(apiVersion === V3, 'executeModel: SQL Model API requires CARTO 3+');
2235
+ assert(type !== 'tileset', 'executeModel: Tilesets not supported');
2236
+ let url = `${apiBaseUrl}/v3/sql/${connectionName}/model/${model}`;
2237
+ const {
2238
+ data,
2239
+ filters,
2240
+ filtersLogicalOperator = 'and',
2241
+ spatialDataType = 'geo',
2242
+ spatialFiltersMode = 'intersects',
2243
+ spatialFiltersResolution = 0
2244
+ } = source;
2245
+ const queryParams = {
2246
+ type,
2247
+ client: clientId,
2248
+ source: data,
2249
+ params,
2250
+ queryParameters: source.queryParameters || '',
2251
+ filters,
2252
+ filtersLogicalOperator
2253
+ };
2254
+ const spatialDataColumn = source.spatialDataColumn || DEFAULT_GEO_COLUMN;
2255
+ // Picking Model API requires 'spatialDataColumn'.
2256
+ if (model === 'pick') {
2257
+ queryParams.spatialDataColumn = spatialDataColumn;
2258
+ }
2259
+ // API supports multiple filters, we apply it only to spatialDataColumn
2260
+ const spatialFilters = source.spatialFilter ? {
2261
+ [spatialDataColumn]: source.spatialFilter
2262
+ } : undefined;
2263
+ if (spatialFilters) {
2264
+ queryParams.spatialFilters = spatialFilters;
2265
+ queryParams.spatialDataColumn = spatialDataColumn;
2266
+ queryParams.spatialDataType = spatialDataType;
2267
+ }
2268
+ if (spatialDataType !== 'geo') {
2269
+ if (spatialFiltersResolution > 0) {
2270
+ queryParams.spatialFiltersResolution = spatialFiltersResolution;
2271
+ }
2272
+ queryParams.spatialFiltersMode = spatialFiltersMode;
2273
+ }
2274
+ const urlWithSearchParams = url + '?' + objectToURLSearchParams(queryParams).toString();
2275
+ const isGet = urlWithSearchParams.length <= REQUEST_GET_MAX_URL_LENGTH;
2276
+ if (isGet) {
2277
+ url = urlWithSearchParams;
2278
+ }
2279
+ return makeCall({
2280
+ url,
2281
+ accessToken: source.accessToken,
2282
+ opts: _extends({}, opts, {
2283
+ method: isGet ? 'GET' : 'POST'
2284
+ }, !isGet && {
2285
+ body: JSON.stringify(queryParams)
2286
+ })
2287
+ });
2288
+ }
2289
+ function objectToURLSearchParams(object) {
2290
+ const params = new URLSearchParams();
2291
+ for (const key in object) {
2292
+ if (isPureObject(object[key])) {
2293
+ params.append(key, JSON.stringify(object[key]));
2294
+ } else if (Array.isArray(object[key])) {
2295
+ params.append(key, JSON.stringify(object[key]));
2296
+ } else if (object[key] === null) {
2297
+ params.append(key, 'null');
2298
+ } else if (object[key] !== undefined) {
2299
+ params.append(key, String(object[key]));
2300
+ }
2301
+ }
2302
+ return params;
2303
+ }
2304
+
2305
+ const _excluded = ["signal", "filters", "filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState"],
2306
+ _excluded2 = ["abortController", "signal", "filters", "filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState"],
2307
+ _excluded3 = ["abortController", "signal", "filters", "filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "operationExp"],
2308
+ _excluded4 = ["abortController", "signal", "filters", "filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState"],
2309
+ _excluded5 = ["abortController", "signal", "filters", "filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState"],
2310
+ _excluded6 = ["abortController", "signal", "filters", "filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState"],
2311
+ _excluded7 = ["abortController", "signal", "filters", "filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState"],
2312
+ _excluded8 = ["abortController", "signal", "filters", "filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState"];
2313
+ /**
2314
+ * Source for Widget API requests.
2315
+ *
2316
+ * Abstract class. Use {@link WidgetQuerySource} or {@link WidgetTableSource}.
2317
+ */
2318
+ class WidgetRemoteSource extends WidgetSource {
2319
+ async getCategories(options) {
2320
+ const {
2321
+ signal,
2322
+ filters = this.props.filters,
2323
+ filterOwner,
2324
+ spatialFilter,
2325
+ spatialFiltersMode,
2326
+ spatialIndexReferenceViewState
2327
+ } = options,
2328
+ params = _objectWithoutPropertiesLoose(options, _excluded);
2329
+ const {
2330
+ column,
2331
+ operation,
2332
+ operationColumn
2333
+ } = params;
2334
+ const source = this.getModelSource(filters, filterOwner);
2335
+ const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
2336
+ return executeModel({
2337
+ model: 'category',
2338
+ source: _extends({}, source, {
2339
+ spatialFiltersResolution,
2340
+ spatialFiltersMode,
2341
+ spatialFilter
2342
+ }),
2343
+ params: {
2344
+ column,
2345
+ operation,
2346
+ operationColumn: operationColumn || column
2347
+ },
2348
+ opts: {
2349
+ signal,
2350
+ headers: this.props.headers
2351
+ }
2352
+ }).then(res => normalizeObjectKeys(res.rows));
2353
+ }
2354
+ async getFeatures(options) {
2355
+ const {
2356
+ abortController,
2357
+ signal = abortController == null ? void 0 : abortController.signal,
2358
+ filters = this.props.filters,
2359
+ filterOwner,
2360
+ spatialFilter,
2361
+ spatialFiltersMode,
2362
+ spatialIndexReferenceViewState
2363
+ } = options,
2364
+ params = _objectWithoutPropertiesLoose(options, _excluded2);
2365
+ const {
2366
+ columns,
2367
+ dataType,
2368
+ featureIds,
2369
+ z,
2370
+ limit,
2371
+ tileResolution
2372
+ } = params;
2373
+ const source = this.getModelSource(filters, filterOwner);
2374
+ const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
2375
+ return executeModel({
2376
+ model: 'pick',
2377
+ source: _extends({}, source, {
2378
+ spatialFiltersResolution,
2379
+ spatialFiltersMode,
2380
+ spatialFilter
2381
+ }),
2382
+ params: {
2383
+ columns,
2384
+ dataType,
2385
+ featureIds,
2386
+ z,
2387
+ limit: limit || 1000,
2388
+ tileResolution: tileResolution || DEFAULT_TILE_RESOLUTION
2389
+ },
2390
+ opts: {
2391
+ signal,
2392
+ headers: this.props.headers
2393
+ }
2394
+ // Avoid `normalizeObjectKeys()`, which changes column names.
2395
+ }).then(({
2396
+ rows
2397
+ }) => ({
2398
+ rows
2399
+ }));
2400
+ }
2401
+ async getFormula(options) {
2402
+ const {
2403
+ abortController,
2404
+ signal = abortController == null ? void 0 : abortController.signal,
2405
+ filters = this.props.filters,
2406
+ filterOwner,
2407
+ spatialFilter,
2408
+ spatialFiltersMode,
2409
+ spatialIndexReferenceViewState,
2410
+ operationExp
2411
+ } = options,
2412
+ params = _objectWithoutPropertiesLoose(options, _excluded3);
2413
+ const {
2414
+ column,
2415
+ operation
2416
+ } = params;
2417
+ const source = this.getModelSource(filters, filterOwner);
2418
+ const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
2419
+ return executeModel({
2420
+ model: 'formula',
2421
+ source: _extends({}, source, {
2422
+ spatialFiltersResolution,
2423
+ spatialFiltersMode,
2424
+ spatialFilter
2425
+ }),
2426
+ params: {
2427
+ column: column != null ? column : '*',
2428
+ operation: operation != null ? operation : 'count',
2429
+ operationExp
2430
+ },
2431
+ opts: {
2432
+ signal,
2433
+ headers: this.props.headers
2434
+ }
2435
+ }).then(res => normalizeObjectKeys(res.rows[0]));
2436
+ }
2437
+ async getHistogram(options) {
2438
+ const {
2439
+ abortController,
2440
+ signal = abortController == null ? void 0 : abortController.signal,
2441
+ filters = this.props.filters,
2442
+ filterOwner,
2443
+ spatialFilter,
2444
+ spatialFiltersMode,
2445
+ spatialIndexReferenceViewState
2446
+ } = options,
2447
+ params = _objectWithoutPropertiesLoose(options, _excluded4);
2448
+ const {
2449
+ column,
2450
+ operation,
2451
+ ticks
2452
+ } = params;
2453
+ const source = this.getModelSource(filters, filterOwner);
2454
+ const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
2455
+ const data = await executeModel({
2456
+ model: 'histogram',
2457
+ source: _extends({}, source, {
2458
+ spatialFiltersResolution,
2459
+ spatialFiltersMode,
2460
+ spatialFilter
2461
+ }),
2462
+ params: {
2463
+ column,
2464
+ operation,
2465
+ ticks
2466
+ },
2467
+ opts: {
2468
+ signal,
2469
+ headers: this.props.headers
2470
+ }
2471
+ }).then(res => normalizeObjectKeys(res.rows));
2472
+ if (data.length) {
2473
+ // Given N ticks the API returns up to N+1 bins, omitting any empty bins. Bins
2474
+ // include 1 bin below the lowest tick, N-1 between ticks, and 1 bin above the highest tick.
2475
+ const result = Array(ticks.length + 1).fill(0);
2476
+ data.forEach(({
2477
+ tick,
2478
+ value
2479
+ }) => result[tick] = value);
2480
+ return result;
2481
+ }
2482
+ return [];
2483
+ }
2484
+ async getRange(options) {
2485
+ const {
2486
+ abortController,
2487
+ signal = abortController == null ? void 0 : abortController.signal,
2488
+ filters = this.props.filters,
2489
+ filterOwner,
2490
+ spatialFilter,
2491
+ spatialFiltersMode,
2492
+ spatialIndexReferenceViewState
2493
+ } = options,
2494
+ params = _objectWithoutPropertiesLoose(options, _excluded5);
2495
+ const {
2496
+ column
2497
+ } = params;
2498
+ const source = this.getModelSource(filters, filterOwner);
2499
+ const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
2500
+ return executeModel({
2501
+ model: 'range',
2502
+ source: _extends({}, source, {
2503
+ spatialFiltersResolution,
2504
+ spatialFiltersMode,
2505
+ spatialFilter
2506
+ }),
2507
+ params: {
2508
+ column
2509
+ },
2510
+ opts: {
2511
+ signal,
2512
+ headers: this.props.headers
2513
+ }
2514
+ }).then(res => normalizeObjectKeys(res.rows[0]));
2515
+ }
2516
+ async getScatter(options) {
2517
+ const {
2518
+ abortController,
2519
+ signal = abortController == null ? void 0 : abortController.signal,
2520
+ filters = this.props.filters,
2521
+ filterOwner,
2522
+ spatialFilter,
2523
+ spatialFiltersMode,
2524
+ spatialIndexReferenceViewState
2525
+ } = options,
2526
+ params = _objectWithoutPropertiesLoose(options, _excluded6);
2527
+ const {
2528
+ xAxisColumn,
2529
+ xAxisJoinOperation,
2530
+ yAxisColumn,
2531
+ yAxisJoinOperation
2532
+ } = params;
2533
+ const source = this.getModelSource(filters, filterOwner);
2534
+ const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
2535
+ // Make sure this is sync with the same constant in cloud-native/maps-api
2536
+ const HARD_LIMIT = 500;
2537
+ return executeModel({
2538
+ model: 'scatterplot',
2539
+ source: _extends({}, source, {
2540
+ spatialFiltersResolution,
2541
+ spatialFiltersMode,
2542
+ spatialFilter
2543
+ }),
2544
+ params: {
2545
+ xAxisColumn,
2546
+ xAxisJoinOperation,
2547
+ yAxisColumn,
2548
+ yAxisJoinOperation,
2549
+ limit: HARD_LIMIT
2550
+ },
2551
+ opts: {
2552
+ signal,
2553
+ headers: this.props.headers
2554
+ }
2555
+ }).then(res => normalizeObjectKeys(res.rows)).then(res => res.map(({
2556
+ x,
2557
+ y
2558
+ }) => [x, y]));
2559
+ }
2560
+ async getTable(options) {
2561
+ const {
2562
+ abortController,
2563
+ signal = abortController == null ? void 0 : abortController.signal,
2564
+ filters = this.props.filters,
2565
+ filterOwner,
2566
+ spatialFilter,
2567
+ spatialFiltersMode,
2568
+ spatialIndexReferenceViewState
2569
+ } = options,
2570
+ params = _objectWithoutPropertiesLoose(options, _excluded7);
2571
+ const {
2572
+ columns,
2573
+ sortBy,
2574
+ sortDirection,
2575
+ offset = 0,
2576
+ limit = 10
2577
+ } = params;
2578
+ const source = this.getModelSource(filters, filterOwner);
2579
+ const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
2580
+ return executeModel({
2581
+ model: 'table',
2582
+ source: _extends({}, source, {
2583
+ spatialFiltersResolution,
2584
+ spatialFiltersMode,
2585
+ spatialFilter
2586
+ }),
2587
+ params: {
2588
+ column: columns,
2589
+ sortBy,
2590
+ sortDirection,
2591
+ limit,
2592
+ offset
2593
+ },
2594
+ opts: {
2595
+ signal,
2596
+ headers: this.props.headers
2597
+ }
2598
+ }).then(res => {
2599
+ var _res$rows, _res$metadata$total, _res$metadata, _res$METADATA;
2600
+ return {
2601
+ // Avoid `normalizeObjectKeys()`, which changes column names.
2602
+ rows: (_res$rows = res.rows) != null ? _res$rows : res.ROWS,
2603
+ 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
2604
+ };
2605
+ });
2606
+ }
2607
+ async getTimeSeries(options) {
2608
+ const {
2609
+ abortController,
2610
+ signal = abortController == null ? void 0 : abortController.signal,
2611
+ filters = this.props.filters,
2612
+ filterOwner,
2613
+ spatialFilter,
2614
+ spatialFiltersMode,
2615
+ spatialIndexReferenceViewState
2616
+ } = options,
2617
+ params = _objectWithoutPropertiesLoose(options, _excluded8);
2618
+ const {
2619
+ column,
2620
+ operationColumn,
2621
+ joinOperation,
2622
+ operation,
2623
+ stepSize,
2624
+ stepMultiplier,
2625
+ splitByCategory,
2626
+ splitByCategoryLimit,
2627
+ splitByCategoryValues
2628
+ } = params;
2629
+ const source = this.getModelSource(filters, filterOwner);
2630
+ const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
2631
+ return executeModel({
2632
+ model: 'timeseries',
2633
+ source: _extends({}, source, {
2634
+ spatialFiltersResolution,
2635
+ spatialFiltersMode,
2636
+ spatialFilter
2637
+ }),
2638
+ params: {
2639
+ column,
2640
+ stepSize,
2641
+ stepMultiplier,
2642
+ operationColumn: operationColumn || column,
2643
+ joinOperation,
2644
+ operation,
2645
+ splitByCategory,
2646
+ splitByCategoryLimit,
2647
+ splitByCategoryValues
2648
+ },
2649
+ opts: {
2650
+ signal,
2651
+ headers: this.props.headers
2652
+ }
2653
+ }).then(res => {
2654
+ var _res$metadata2;
2655
+ return {
2656
+ rows: normalizeObjectKeys(res.rows),
2657
+ categories: (_res$metadata2 = res.metadata) == null ? void 0 : _res$metadata2.categories
2658
+ };
2659
+ });
2660
+ }
2661
+ }
2662
+
2663
+ /**
2664
+ * Source for Widget API requests on a data source defined by a SQL query.
2665
+ *
2666
+ * Generally not intended to be constructed directly. Instead, call
2667
+ * {@link vectorQuerySource}, {@link h3QuerySource}, or {@link quadbinQuerySource},
2668
+ * which can be shared with map layers. Sources contain a `widgetSource` property,
2669
+ * for use by widget implementations.
2670
+ *
2671
+ * Example:
2672
+ *
2673
+ * ```javascript
2674
+ * import { vectorQuerySource } from '@carto/api-client';
2675
+ *
2676
+ * const data = vectorQuerySource({
2677
+ * accessToken: '••••',
2678
+ * connectionName: 'carto_dw',
2679
+ * sqlQuery: 'SELECT * FROM carto-demo-data.demo_tables.retail_stores'
2680
+ * });
2681
+ *
2682
+ * const { widgetSource } = await data;
2683
+ * ```
2684
+ */
2685
+ class WidgetQuerySource extends WidgetRemoteSource {
2686
+ getModelSource(filters, filterOwner) {
2687
+ return _extends({}, super._getModelSource(filters, filterOwner), {
2688
+ type: 'query',
2689
+ data: this.props.sqlQuery,
2690
+ queryParameters: this.props.queryParameters
2691
+ });
2692
+ }
2693
+ }
2694
+
2695
+ /**
2696
+ * Source for Widget API requests on a data source defined as a table.
2697
+ *
2698
+ * Generally not intended to be constructed directly. Instead, call
2699
+ * {@link vectorTableSource}, {@link h3TableSource}, or {@link quadbinTableSource},
2700
+ * which can be shared with map layers. Sources contain a `widgetSource` property,
2701
+ * for use by widget implementations.
2702
+ *
2703
+ * Example:
2704
+ *
2705
+ * ```javascript
2706
+ * import { vectorTableSource } from '@carto/api-client';
2707
+ *
2708
+ * const data = vectorTableSource({
2709
+ * accessToken: '••••',
2710
+ * connectionName: 'carto_dw',
2711
+ * tableName: 'carto-demo-data.demo_tables.retail_stores'
2712
+ * });
2713
+ *
2714
+ * const { widgetSource } = await data;
2715
+ * ```
2716
+ */
2717
+ class WidgetTableSource extends WidgetRemoteSource {
2718
+ getModelSource(filters, filterOwner) {
2719
+ return _extends({}, super._getModelSource(filters, filterOwner), {
2720
+ type: 'table',
2721
+ data: this.props.tableName
2722
+ });
2723
+ }
2724
+ }
2725
+
2726
+ /** @privateRemarks Source: @carto/react-core */
2727
+ const aggregationFunctions = {
2728
+ count: values => values.length,
2729
+ min: (...args) => applyAggregationFunction(min, ...args),
2730
+ max: (...args) => applyAggregationFunction(max, ...args),
2731
+ sum: (...args) => applyAggregationFunction(sum, ...args),
2732
+ avg: (...args) => applyAggregationFunction(avg, ...args)
2733
+ };
2734
+ /** @privateRemarks Source: @carto/react-core */
2735
+ function aggregate(feature, keys, operation) {
2736
+ if (!(keys != null && keys.length)) {
2737
+ throw new Error('Cannot aggregate a feature without having keys');
2738
+ } else if (keys.length === 1) {
2739
+ const value = feature[keys[0]];
2740
+ return isPotentiallyValidNumber(value) ? Number(value) : value;
2741
+ }
2742
+ const aggregationFn = aggregationFunctions[operation];
2743
+ if (!aggregationFn) {
2744
+ throw new Error(`${operation} isn't a valid aggregation function`);
2745
+ }
2746
+ return aggregationFn(keys.map(column => {
2747
+ const value = feature[column];
2748
+ return isPotentiallyValidNumber(value) ? Number(value) : value;
2749
+ }));
2750
+ }
2751
+ /*
2752
+ * Forced casting to Number (just of non empty strings) allows to work-around
2753
+ * some specific situations, where a big numeric field is transformed into a string when generating the tileset(eg.PG)
2754
+ */
2755
+ function isPotentiallyValidNumber(value) {
2756
+ return typeof value === 'string' && value.trim().length > 0;
2757
+ }
2758
+ const applyAggregationFunction = (aggFn, values, keys, operation) => {
2759
+ const normalizedKeys = normalizeKeys(keys);
2760
+ const elements = ((normalizedKeys == null ? void 0 : normalizedKeys.length) || 0) <= 1 ? filterFalsyElements(values, normalizedKeys || []) : values;
2761
+ return aggFn(elements, keys, operation);
2762
+ };
2763
+ function filterFalsyElements(values, keys) {
2764
+ const filterFn = value => value !== null && value !== undefined;
2765
+ if (!(keys != null && keys.length)) {
2766
+ return values.filter(filterFn);
2767
+ }
2768
+ return values.filter(v => filterFn(v[keys[0]]));
2769
+ }
2770
+ // Aggregation functions
2771
+ function avg(values, keys, joinOperation) {
2772
+ return sum(values, keys, joinOperation) / (values.length || 1);
2773
+ }
2774
+ function sum(values, keys, joinOperation) {
2775
+ const normalizedKeys = normalizeKeys(keys);
2776
+ if (normalizedKeys) {
2777
+ return values.reduce((a, b) => a + aggregate(b, normalizedKeys, joinOperation), 0);
2778
+ }
2779
+ return values.reduce((a, b) => a + b, 0);
2780
+ }
2781
+ function min(values, keys, joinOperation) {
2782
+ const normalizedKeys = normalizeKeys(keys);
2783
+ if (normalizedKeys) {
2784
+ return values.reduce((a, b) => Math.min(a, aggregate(b, normalizedKeys, joinOperation)), Infinity);
2785
+ }
2786
+ return Math.min(...values);
2787
+ }
2788
+ function max(values, keys, joinOperation) {
2789
+ const normalizedKeys = normalizeKeys(keys);
2790
+ if (normalizedKeys) {
2791
+ return values.reduce((a, b) => Math.max(a, aggregate(b, normalizedKeys, joinOperation)), -Infinity);
2792
+ }
2793
+ return Math.max(...values);
2794
+ }
2795
+ // Aux
2796
+ // Keys can come as a string (one column) or a strings array (multiple column)
2797
+ // Use always an array to make the code easier
2798
+ function normalizeKeys(keys) {
2799
+ return Array.isArray(keys) ? keys : typeof keys === 'string' ? [keys] : undefined;
2800
+ }
2801
+
2802
+ /***
2803
+ Copyright 2013 Teun Duynstee
2804
+
2805
+ Licensed under the Apache License, Version 2.0 (the "License");
2806
+ you may not use this file except in compliance with the License.
2807
+ You may obtain a copy of the License at
2808
+
2809
+ http://www.apache.org/licenses/LICENSE-2.0
2810
+
2811
+ Unless required by applicable law or agreed to in writing, software
2812
+ distributed under the License is distributed on an "AS IS" BASIS,
2813
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2814
+ See the License for the specific language governing permissions and
2815
+ limitations under the License.
2816
+ */
2817
+ var thenBy_module = function () {
2818
+ function identity(v) {
2819
+ return v;
2820
+ }
2821
+ function ignoreCase(v) {
2822
+ return typeof v === "string" ? v.toLowerCase() : v;
2823
+ }
2824
+ function makeCompareFunction(f, opt) {
2825
+ opt = typeof opt === "object" ? opt : {
2826
+ direction: opt
2827
+ };
2828
+ if (typeof f != "function") {
2829
+ var prop = f;
2830
+ // make unary function
2831
+ f = function (v1) {
2832
+ return !!v1[prop] ? v1[prop] : "";
2833
+ };
2834
+ }
2835
+ if (f.length === 1) {
2836
+ // f is a unary function mapping a single item to its sort score
2837
+ var uf = f;
2838
+ var preprocess = opt.ignoreCase ? ignoreCase : identity;
2839
+ var cmp = opt.cmp || function (v1, v2) {
2840
+ return v1 < v2 ? -1 : v1 > v2 ? 1 : 0;
2841
+ };
2842
+ f = function (v1, v2) {
2843
+ return cmp(preprocess(uf(v1)), preprocess(uf(v2)));
2844
+ };
2845
+ }
2846
+ const descTokens = {
2847
+ "-1": '',
2848
+ desc: ''
2849
+ };
2850
+ if (opt.direction in descTokens) return function (v1, v2) {
2851
+ return -f(v1, v2);
2852
+ };
2853
+ return f;
2854
+ }
2855
+
2856
+ /* adds a secondary compare function to the target function (`this` context)
2857
+ which is applied in case the first one returns 0 (equal)
2858
+ returns a new compare function, which has a `thenBy` method as well */
2859
+ function tb(func, opt) {
2860
+ /* should get value false for the first call. This can be done by calling the
2861
+ exported function, or the firstBy property on it (for es6 module compatibility)
2862
+ */
2863
+ var x = typeof this == "function" && !this.firstBy ? this : false;
2864
+ var y = makeCompareFunction(func, opt);
2865
+ var f = x ? function (a, b) {
2866
+ return x(a, b) || y(a, b);
2867
+ } : y;
2868
+ f.thenBy = tb;
2869
+ return f;
2870
+ }
2871
+ tb.firstBy = tb;
2872
+ return tb;
2873
+ }();
2874
+
2875
+ /**
2876
+ * Apply sort structure to a collection of features
2877
+ * @param features
2878
+ * @param [sortOptions]
2879
+ * @param [sortOptions.sortBy] - One or more columns to sort by
2880
+ * @param [sortOptions.sortByDirection] - Direction by the columns will be sorted
2881
+ * @param [sortOptions.sortByColumnType] - Column type
2882
+ * @internal
2883
+ * @privateRemarks Source: @carto/react-core
2884
+ */
2885
+ function applySorting(features, {
2886
+ sortBy,
2887
+ sortByDirection = 'asc',
2888
+ sortByColumnType = 'string'
2889
+ } = {}) {
2890
+ // If sortBy is undefined, pass all features
2891
+ if (sortBy === undefined) {
2892
+ return features;
2893
+ }
2894
+ // sortOptions exists, but are bad formatted
2895
+ const isValidSortBy = Array.isArray(sortBy) && sortBy.length ||
2896
+ // sortBy can be an array of columns
2897
+ typeof sortBy === 'string'; // or just one column
2898
+ if (!isValidSortBy) {
2899
+ throw new Error('Sorting options are bad formatted');
2900
+ }
2901
+ const sortFn = createSortFn({
2902
+ sortBy,
2903
+ sortByDirection,
2904
+ sortByColumnType: sortByColumnType || 'string'
2905
+ });
2906
+ return features.sort(sortFn);
2907
+ }
2908
+ // Aux
2909
+ function createSortFn({
2910
+ sortBy,
2911
+ sortByDirection,
2912
+ sortByColumnType
2913
+ }) {
2914
+ const [firstSortOption, ...othersSortOptions] = normalizeSortByOptions({
2915
+ sortBy,
2916
+ sortByDirection,
2917
+ sortByColumnType
2918
+ });
2919
+ let sortFn = thenBy_module.firstBy(...firstSortOption);
2920
+ for (const sortOptions of othersSortOptions) {
2921
+ sortFn = sortFn.thenBy(...sortOptions);
2922
+ }
2923
+ return sortFn;
2924
+ }
2925
+ function normalizeSortByOptions({
2926
+ sortBy,
2927
+ sortByDirection,
2928
+ sortByColumnType
2929
+ }) {
2930
+ const numberFormat = sortByColumnType === 'number' && {
2931
+ cmp: (a, b) => a - b
2932
+ };
2933
+ if (!Array.isArray(sortBy)) {
2934
+ sortBy = [sortBy];
2935
+ }
2936
+ return sortBy.map(sortByEl => {
2937
+ // sortByEl is 'column'
2938
+ if (typeof sortByEl === 'string') {
2939
+ return [sortByEl, _extends({
2940
+ direction: sortByDirection
2941
+ }, numberFormat)];
2942
+ }
2943
+ if (Array.isArray(sortByEl)) {
2944
+ // sortBy is ['column']
2945
+ if (sortByEl[1] === undefined) {
2946
+ return [sortByEl, _extends({
2947
+ direction: sortByDirection
2948
+ }, numberFormat)];
2949
+ }
2950
+ // sortBy is ['column', { ... }]
2951
+ if (typeof sortByEl[1] === 'object') {
2952
+ const othersSortOptions = numberFormat ? _extends({}, numberFormat, sortByEl[1]) : sortByEl[1];
2953
+ return [sortByEl[0], _extends({
2954
+ direction: sortByDirection
2955
+ }, othersSortOptions)];
2956
+ }
2957
+ }
2958
+ return sortByEl;
2959
+ });
2960
+ }
2961
+
2962
+ /** @privateRemarks Source: @carto/react-core */
2963
+ function groupValuesByColumn({
2964
+ data,
2965
+ valuesColumns,
2966
+ joinOperation,
2967
+ keysColumn,
2968
+ operation
2969
+ }) {
2970
+ if (Array.isArray(data) && data.length === 0) {
2971
+ return null;
2972
+ }
2973
+ const groups = data.reduce((accumulator, item) => {
2974
+ const group = item[keysColumn];
2975
+ const values = accumulator.get(group) || [];
2976
+ accumulator.set(group, values);
2977
+ const aggregatedValue = aggregate(item, valuesColumns, joinOperation);
2978
+ const isValid = (operation === 'count' ? true : aggregatedValue !== null) && aggregatedValue !== undefined;
2979
+ if (isValid) {
2980
+ values.push(aggregatedValue);
2981
+ accumulator.set(group, values);
2982
+ }
2983
+ return accumulator;
2984
+ }, new Map()); // We use a map to be able to maintain the type in the key value
2985
+ const targetOperation = aggregationFunctions[operation];
2986
+ if (targetOperation) {
2987
+ return Array.from(groups).map(([name, value]) => ({
2988
+ name,
2989
+ value: targetOperation(value)
2990
+ }));
2991
+ }
2992
+ return [];
2993
+ }
2994
+
2995
+ /**
2996
+ * Returns midnight (local time) on the Monday preceeding a given date, in
2997
+ * milliseconds since the UNIX epoch.
2998
+ */
2999
+ /**
3000
+ * Returns midnight (UTC) on the Monday preceeding a given date, in
3001
+ * milliseconds since the UNIX epoch.
3002
+ */
3003
+ function getUTCMonday(date) {
3004
+ const dateCp = new Date(date);
3005
+ const day = dateCp.getUTCDay();
3006
+ const diff = dateCp.getUTCDate() - day + (day ? 1 : -6); // adjust when day is sunday
3007
+ dateCp.setUTCDate(diff);
3008
+ return Date.UTC(dateCp.getUTCFullYear(), dateCp.getUTCMonth(), dateCp.getUTCDate());
3009
+ }
3010
+
3011
+ const GROUP_KEY_FN_MAPPING = {
3012
+ year: date => Date.UTC(date.getUTCFullYear()),
3013
+ month: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth()),
3014
+ week: date => getUTCMonday(date),
3015
+ day: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()),
3016
+ hour: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours()),
3017
+ minute: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes()),
3018
+ second: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds())
3019
+ };
3020
+ /** @privateRemarks Source: @carto/react-core */
3021
+ function groupValuesByDateColumn({
3022
+ data,
3023
+ valuesColumns,
3024
+ joinOperation,
3025
+ keysColumn,
3026
+ groupType,
3027
+ operation
3028
+ }) {
3029
+ if (Array.isArray(data) && data.length === 0) {
3030
+ return null;
3031
+ }
3032
+ const groupKeyFn = GROUP_KEY_FN_MAPPING[groupType];
3033
+ if (!groupKeyFn) {
3034
+ return null;
3035
+ }
3036
+ const groups = data.reduce((acc, item) => {
3037
+ const value = item[keysColumn];
3038
+ const formattedValue = new Date(value);
3039
+ const groupKey = groupKeyFn(formattedValue);
3040
+ if (!isNaN(groupKey)) {
3041
+ let groupedValues = acc.get(groupKey);
3042
+ if (!groupedValues) {
3043
+ groupedValues = [];
3044
+ acc.set(groupKey, groupedValues);
3045
+ }
3046
+ const aggregatedValue = aggregate(item, valuesColumns, joinOperation);
3047
+ const isValid = aggregatedValue !== null && aggregatedValue !== undefined;
3048
+ if (isValid) {
3049
+ groupedValues.push(aggregatedValue);
3050
+ acc.set(groupKey, groupedValues);
3051
+ }
3052
+ }
3053
+ return acc;
3054
+ }, new Map());
3055
+ const targetOperation = aggregationFunctions[operation];
3056
+ return [...groups.entries()].map(([name, value]) => ({
3057
+ name,
3058
+ value: targetOperation(value)
3059
+ })).sort((a, b) => a.name - b.name);
3060
+ }
3061
+
3062
+ /**
3063
+ * Histogram computation.
3064
+ * @privateRemarks Source: @carto/react-core
3065
+ */
3066
+ function histogram({
3067
+ data,
3068
+ valuesColumns,
3069
+ joinOperation,
3070
+ ticks,
3071
+ operation
3072
+ }) {
3073
+ if (Array.isArray(data) && data.length === 0) {
3074
+ return [];
3075
+ }
3076
+ const binsContainer = [Number.MIN_SAFE_INTEGER, ...ticks].map((tick, index, arr) => ({
3077
+ bin: index,
3078
+ start: tick,
3079
+ end: index === arr.length - 1 ? Number.MAX_SAFE_INTEGER : arr[index + 1],
3080
+ values: []
3081
+ }));
3082
+ data.forEach(feature => {
3083
+ const featureValue = aggregate(feature, valuesColumns, joinOperation);
3084
+ const isValid = featureValue !== null && featureValue !== undefined;
3085
+ if (!isValid) {
3086
+ return;
3087
+ }
3088
+ const binContainer = binsContainer.find(bin => bin.start <= featureValue && bin.end > featureValue);
3089
+ if (!binContainer) {
3090
+ return;
3091
+ }
3092
+ binContainer.values.push(featureValue);
3093
+ });
3094
+ const targetOperation = aggregationFunctions[operation];
3095
+ const transformedBins = binsContainer.map(binContainer => binContainer.values);
3096
+ return transformedBins.map(values => values.length ? targetOperation(values) : 0);
3097
+ }
3098
+
3099
+ /**
3100
+ * Filters invalid features and formats data.
3101
+ * @privateRemarks Source: @carto/react-core
3102
+ */
3103
+ function scatterPlot({
3104
+ data,
3105
+ xAxisColumns,
3106
+ xAxisJoinOperation,
3107
+ yAxisColumns,
3108
+ yAxisJoinOperation
3109
+ }) {
3110
+ return data.reduce((acc, feature) => {
3111
+ const xValue = aggregate(feature, xAxisColumns, xAxisJoinOperation);
3112
+ const xIsValid = xValue !== null && xValue !== undefined;
3113
+ const yValue = aggregate(feature, yAxisColumns, yAxisJoinOperation);
3114
+ const yIsValid = yValue !== null && yValue !== undefined;
3115
+ if (xIsValid && yIsValid) {
3116
+ acc.push([xValue, yValue]);
3117
+ }
3118
+ return acc;
3119
+ }, []);
3120
+ }
3121
+
3122
+ /**
3123
+ * Source for Widget API requests on a data source defined by a tileset.
3124
+ *
3125
+ * Generally not intended to be constructed directly. Instead, call
3126
+ * {@link vectorTilesetSource}, {@link h3TilesetSource}, or {@link quadbinTilesetSource},
3127
+ * which can be shared with map layers. Sources contain a `widgetSource`
3128
+ * property, for use by widget implementations.
3129
+ *
3130
+ * Example:
3131
+ *
3132
+ * ```javascript
3133
+ * import { vectorTilesetSource } from '@carto/api-client';
3134
+ *
3135
+ * const data = vectorTilesetSource({
3136
+ * accessToken: '••••',
3137
+ * connectionName: 'carto_dw',
3138
+ * tableName: 'carto-demo-data.demo_rasters.my_tileset_source'
3139
+ * });
3140
+ *
3141
+ * const { widgetSource } = await data;
3142
+ * ```
3143
+ */
3144
+ class WidgetTilesetSource extends WidgetSource {
3145
+ constructor(...args) {
3146
+ super(...args);
3147
+ this._tiles = [];
3148
+ this._features = [];
3149
+ this._tileFeatureExtractOptions = {};
3150
+ this._tileFeatureExtractPreviousInputs = {};
3151
+ }
3152
+ getModelSource(filters, filterOwner) {
3153
+ return _extends({}, super._getModelSource(filters, filterOwner), {
3154
+ type: 'tileset',
3155
+ data: this.props.tableName
3156
+ });
3157
+ }
3158
+ /**
3159
+ * Loads features as a list of tiles (typically provided by deck.gl).
3160
+ * After tiles are loaded, {@link extractTileFeatures} must be called
3161
+ * before computing statistics on the tiles.
3162
+ */
3163
+ loadTiles(tiles) {
3164
+ this._tiles = tiles;
3165
+ this._features.length = 0;
3166
+ }
3167
+ /** Configures options used to extract features from tiles. */
3168
+ setTileFeatureExtractOptions(options) {
3169
+ this._tileFeatureExtractOptions = options;
3170
+ this._features.length = 0;
3171
+ }
3172
+ _extractTileFeatures(spatialFilter) {
3173
+ // When spatial filter has not changed, don't redo extraction. If tiles or
3174
+ // tile extract options change, features will have been cleared already.
3175
+ const prevInputs = this._tileFeatureExtractPreviousInputs;
3176
+ if (this._features.length && prevInputs.spatialFilter && booleanEqual(prevInputs.spatialFilter, spatialFilter)) {
3177
+ return;
3178
+ }
3179
+ this._features = tileFeatures(_extends({
3180
+ tiles: this._tiles,
3181
+ tileFormat: this.props.tileFormat
3182
+ }, this._tileFeatureExtractOptions, {
3183
+ spatialFilter,
3184
+ spatialDataColumn: this.props.spatialDataColumn,
3185
+ spatialDataType: this.props.spatialDataType
3186
+ }));
3187
+ prevInputs.spatialFilter = spatialFilter;
3188
+ }
3189
+ /**
3190
+ * Loads features as GeoJSON (used for testing).
3191
+ * @experimental
3192
+ * @internal Not for public use. Spatial filters in other method calls will be ignored.
3193
+ */
3194
+ loadGeoJSON({
3195
+ geojson,
3196
+ spatialFilter
3197
+ }) {
3198
+ this._features = geojsonFeatures(_extends({
3199
+ geojson,
3200
+ spatialFilter
3201
+ }, this._tileFeatureExtractOptions));
3202
+ this._tileFeatureExtractPreviousInputs.spatialFilter = spatialFilter;
3203
+ }
3204
+ async getFeatures() {
3205
+ throw new Error('getFeatures not supported for tilesets');
3206
+ }
3207
+ async getFormula({
3208
+ column = '*',
3209
+ operation = 'count',
3210
+ joinOperation,
3211
+ filters,
3212
+ filterOwner,
3213
+ spatialFilter
3214
+ }) {
3215
+ if (operation === 'custom') {
3216
+ throw new Error('Custom aggregation not supported for tilesets');
3217
+ }
3218
+ // Column is required except when operation is 'count'.
3219
+ if (column && column !== '*' || operation !== 'count') {
3220
+ assertColumn(this._features, column);
3221
+ }
3222
+ const filteredFeatures = this._getFilteredFeatures(spatialFilter, filters, filterOwner);
3223
+ if (filteredFeatures.length === 0 && operation !== 'count') {
3224
+ return {
3225
+ value: null
3226
+ };
3227
+ }
3228
+ const targetOperation = aggregationFunctions[operation];
3229
+ return {
3230
+ value: targetOperation(filteredFeatures, column, joinOperation)
3231
+ };
3232
+ }
3233
+ async getHistogram({
3234
+ operation = 'count',
3235
+ ticks,
3236
+ column,
3237
+ joinOperation,
3238
+ filters,
3239
+ filterOwner,
3240
+ spatialFilter
3241
+ }) {
3242
+ const filteredFeatures = this._getFilteredFeatures(spatialFilter, filters, filterOwner);
3243
+ assertColumn(this._features, column);
3244
+ if (!this._features.length) {
3245
+ return [];
3246
+ }
3247
+ return histogram({
3248
+ data: filteredFeatures,
3249
+ valuesColumns: normalizeColumns(column),
3250
+ joinOperation,
3251
+ ticks,
3252
+ operation
3253
+ });
3254
+ }
3255
+ async getCategories({
3256
+ column,
3257
+ operation = 'count',
3258
+ operationColumn,
3259
+ joinOperation,
3260
+ filters,
3261
+ filterOwner,
3262
+ spatialFilter
3263
+ }) {
3264
+ const filteredFeatures = this._getFilteredFeatures(spatialFilter, filters, filterOwner);
3265
+ if (!filteredFeatures.length) {
3266
+ return [];
3267
+ }
3268
+ assertColumn(this._features, column, operationColumn);
3269
+ const groups = groupValuesByColumn({
3270
+ data: filteredFeatures,
3271
+ valuesColumns: normalizeColumns(operationColumn || column),
3272
+ joinOperation,
3273
+ keysColumn: column,
3274
+ operation
3275
+ });
3276
+ return groups || [];
3277
+ }
3278
+ async getScatter({
3279
+ xAxisColumn,
3280
+ yAxisColumn,
3281
+ xAxisJoinOperation,
3282
+ yAxisJoinOperation,
3283
+ filters,
3284
+ filterOwner,
3285
+ spatialFilter
3286
+ }) {
3287
+ const filteredFeatures = this._getFilteredFeatures(spatialFilter, filters, filterOwner);
3288
+ if (!filteredFeatures.length) {
3289
+ return [];
3290
+ }
3291
+ assertColumn(this._features, xAxisColumn, yAxisColumn);
3292
+ return scatterPlot({
3293
+ data: filteredFeatures,
3294
+ xAxisColumns: normalizeColumns(xAxisColumn),
3295
+ xAxisJoinOperation,
3296
+ yAxisColumns: normalizeColumns(yAxisColumn),
3297
+ yAxisJoinOperation
3298
+ });
3299
+ }
3300
+ async getTable({
3301
+ columns,
3302
+ searchFilterColumn,
3303
+ searchFilterText,
3304
+ sortBy,
3305
+ sortDirection,
3306
+ sortByColumnType,
3307
+ offset = 0,
3308
+ limit = 10,
3309
+ filters,
3310
+ filterOwner,
3311
+ spatialFilter
3312
+ }) {
3313
+ // Filter.
3314
+ let filteredFeatures = this._getFilteredFeatures(spatialFilter, filters, filterOwner);
3315
+ if (!filteredFeatures.length) {
3316
+ return {
3317
+ rows: [],
3318
+ totalCount: 0
3319
+ };
3320
+ }
3321
+ // Search.
3322
+ if (searchFilterColumn && searchFilterText) {
3323
+ filteredFeatures = filteredFeatures.filter(row => row[searchFilterColumn] && String(row[searchFilterColumn]).toLowerCase().includes(String(searchFilterText).toLowerCase()));
3324
+ }
3325
+ // Sort.
3326
+ let rows = applySorting(filteredFeatures, {
3327
+ sortBy,
3328
+ sortByDirection: sortDirection,
3329
+ sortByColumnType
3330
+ });
3331
+ const totalCount = rows.length;
3332
+ // Offset and limit.
3333
+ rows = rows.slice(Math.min(offset, totalCount), Math.min(offset + limit, totalCount));
3334
+ // Select columns.
3335
+ rows = rows.map(srcRow => {
3336
+ const dstRow = {};
3337
+ for (const column of columns) {
3338
+ dstRow[column] = srcRow[column];
3339
+ }
3340
+ return dstRow;
3341
+ });
3342
+ return {
3343
+ rows,
3344
+ totalCount
3345
+ };
3346
+ }
3347
+ async getTimeSeries({
3348
+ column,
3349
+ stepSize,
3350
+ operation,
3351
+ operationColumn,
3352
+ joinOperation,
3353
+ filters,
3354
+ filterOwner,
3355
+ spatialFilter
3356
+ }) {
3357
+ const filteredFeatures = this._getFilteredFeatures(spatialFilter, filters, filterOwner);
3358
+ if (!filteredFeatures.length) {
3359
+ return {
3360
+ rows: []
3361
+ };
3362
+ }
3363
+ assertColumn(this._features, column, operationColumn);
3364
+ const rows = groupValuesByDateColumn({
3365
+ data: filteredFeatures,
3366
+ valuesColumns: normalizeColumns(operationColumn || column),
3367
+ keysColumn: column,
3368
+ groupType: stepSize,
3369
+ operation,
3370
+ joinOperation
3371
+ }) || [];
3372
+ return {
3373
+ rows
3374
+ };
3375
+ }
3376
+ async getRange({
3377
+ column,
3378
+ filters,
3379
+ filterOwner,
3380
+ spatialFilter
3381
+ }) {
3382
+ assertColumn(this._features, column);
3383
+ const filteredFeatures = this._getFilteredFeatures(spatialFilter, filters, filterOwner);
3384
+ if (!this._features.length) {
3385
+ // TODO: Is this the only nullable response in the Widgets API? If so,
3386
+ // can we do something more consistent?
3387
+ return null;
3388
+ }
3389
+ return {
3390
+ min: aggregationFunctions.min(filteredFeatures, column),
3391
+ max: aggregationFunctions.max(filteredFeatures, column)
3392
+ };
3393
+ }
3394
+ /****************************************************************************
3395
+ * INTERNAL
3396
+ */
3397
+ _getFilteredFeatures(spatialFilter, filters, filterOwner) {
3398
+ assert(spatialFilter, 'spatialFilter required for tilesets');
3399
+ this._extractTileFeatures(spatialFilter);
3400
+ return applyFilters(this._features, getApplicableFilters(filterOwner, filters || this.props.filters), this.props.filtersLogicalOperator || 'and');
3401
+ }
3402
+ }
3403
+ function assertColumn(features, ...columnArgs) {
3404
+ // TODO(cleanup): Can drop support for multiple column shapes here?
3405
+ // Due to the multiple column shape, we normalise it as an array with normalizeColumns
3406
+ const columns = Array.from(new Set(columnArgs.map(normalizeColumns).flat()));
3407
+ const featureKeys = Object.keys(features[0]);
3408
+ const invalidColumns = columns.filter(column => !featureKeys.includes(column));
3409
+ if (invalidColumns.length) {
3410
+ throw new InvalidColumnError(`Missing column(s): ${invalidColumns.join(', ')}`);
3411
+ }
3412
+ }
3413
+ function normalizeColumns(columns) {
3414
+ return Array.isArray(columns) ? columns : typeof columns === 'string' ? [columns] : [];
3415
+ }
3416
+
3417
+ const h3QuerySource = async function h3QuerySource(options) {
3418
+ const {
3419
+ aggregationExp,
3420
+ aggregationResLevel = DEFAULT_AGGREGATION_RES_LEVEL_H3,
3421
+ sqlQuery,
3422
+ spatialDataColumn = 'h3',
3423
+ queryParameters,
3424
+ filters
3425
+ } = options;
3426
+ const spatialDataType = 'h3';
3427
+ const urlParameters = {
3428
+ aggregationExp,
3429
+ spatialDataColumn,
3430
+ spatialDataType,
3431
+ q: sqlQuery
3432
+ };
3433
+ if (aggregationResLevel) {
3434
+ urlParameters.aggregationResLevel = String(aggregationResLevel);
3435
+ }
3436
+ if (queryParameters) {
3437
+ urlParameters.queryParameters = queryParameters;
3438
+ }
3439
+ if (filters) {
3440
+ urlParameters.filters = filters;
3441
+ }
3442
+ return baseSource('query', options, urlParameters).then(result => _extends({}, result, {
3443
+ widgetSource: new WidgetQuerySource(_extends({}, options, {
3444
+ // NOTE: Parameters with default values above must be explicitly passed here.
3445
+ spatialDataColumn,
3446
+ spatialDataType
3447
+ }))
3448
+ }));
3449
+ };
3450
+
3451
+ const h3TableSource = async function h3TableSource(options) {
3452
+ const {
3453
+ aggregationExp,
3454
+ aggregationResLevel = DEFAULT_AGGREGATION_RES_LEVEL_H3,
3455
+ spatialDataColumn = 'h3',
3456
+ tableName,
3457
+ filters
3458
+ } = options;
3459
+ const spatialDataType = 'h3';
3460
+ const urlParameters = {
3461
+ aggregationExp,
3462
+ name: tableName,
3463
+ spatialDataColumn,
3464
+ spatialDataType
3465
+ };
3466
+ if (aggregationResLevel) {
3467
+ urlParameters.aggregationResLevel = String(aggregationResLevel);
3468
+ }
3469
+ if (filters) {
3470
+ urlParameters.filters = filters;
3471
+ }
3472
+ return baseSource('table', options, urlParameters).then(result => _extends({}, result, {
3473
+ widgetSource: new WidgetTableSource(_extends({}, options, {
3474
+ // NOTE: Parameters with default values above must be explicitly passed here.
3475
+ spatialDataColumn,
3476
+ spatialDataType
3477
+ }))
3478
+ }));
3479
+ };
3480
+
3481
+ // deck.gl
3482
+ // SPDX-License-Identifier: MIT
3483
+ // Copyright (c) vis.gl contributors
3484
+ const h3TilesetSource = async function h3TilesetSource(options) {
3485
+ const {
3486
+ tableName
3487
+ } = options;
3488
+ const urlParameters = {
3489
+ name: tableName
3490
+ };
3491
+ return baseSource('tileset', options, urlParameters);
3492
+ };
3493
+
3494
+ // deck.gl
3495
+ // SPDX-License-Identifier: MIT
3496
+ // Copyright (c) vis.gl contributors
3497
+ const rasterSource = async function rasterSource(options) {
3498
+ const {
3499
+ tableName,
3500
+ filters
3501
+ } = options;
3502
+ const urlParameters = {
3503
+ name: tableName
3504
+ };
3505
+ if (filters) {
3506
+ urlParameters.filters = filters;
3507
+ }
3508
+ return baseSource('raster', options, urlParameters);
3509
+ };
3510
+
3511
+ const quadbinQuerySource = async function quadbinQuerySource(options) {
3512
+ const {
3513
+ aggregationExp,
3514
+ aggregationResLevel = DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN,
3515
+ sqlQuery,
3516
+ spatialDataColumn = 'quadbin',
3517
+ queryParameters,
3518
+ filters
3519
+ } = options;
3520
+ const spatialDataType = 'quadbin';
3521
+ const urlParameters = {
3522
+ aggregationExp,
3523
+ q: sqlQuery,
3524
+ spatialDataColumn,
3525
+ spatialDataType
3526
+ };
3527
+ if (aggregationResLevel) {
3528
+ urlParameters.aggregationResLevel = String(aggregationResLevel);
3529
+ }
3530
+ if (queryParameters) {
3531
+ urlParameters.queryParameters = queryParameters;
3532
+ }
3533
+ if (filters) {
3534
+ urlParameters.filters = filters;
3535
+ }
3536
+ return baseSource('query', options, urlParameters).then(result => _extends({}, result, {
3537
+ widgetSource: new WidgetQuerySource(_extends({}, options, {
3538
+ // NOTE: Parameters with default values above must be explicitly passed here.
3539
+ spatialDataColumn,
3540
+ spatialDataType
3541
+ }))
3542
+ }));
3543
+ };
3544
+
3545
+ const quadbinTableSource = async function quadbinTableSource(options) {
3546
+ const {
3547
+ aggregationExp,
3548
+ aggregationResLevel = DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN,
3549
+ spatialDataColumn = 'quadbin',
3550
+ tableName,
3551
+ filters
3552
+ } = options;
3553
+ const spatialDataType = 'quadbin';
3554
+ const urlParameters = {
3555
+ aggregationExp,
3556
+ name: tableName,
3557
+ spatialDataColumn,
3558
+ spatialDataType
3559
+ };
3560
+ if (aggregationResLevel) {
3561
+ urlParameters.aggregationResLevel = String(aggregationResLevel);
3562
+ }
3563
+ if (filters) {
3564
+ urlParameters.filters = filters;
3565
+ }
3566
+ return baseSource('table', options, urlParameters).then(result => _extends({}, result, {
3567
+ widgetSource: new WidgetTableSource(_extends({}, options, {
3568
+ // NOTE: Parameters with default values above must be explicitly passed here.
3569
+ spatialDataColumn,
3570
+ spatialDataType
3571
+ }))
3572
+ }));
3573
+ };
3574
+
3575
+ // deck.gl
3576
+ // SPDX-License-Identifier: MIT
3577
+ // Copyright (c) vis.gl contributors
3578
+ const quadbinTilesetSource = async function quadbinTilesetSource(options) {
3579
+ const {
3580
+ tableName
3581
+ } = options;
3582
+ const urlParameters = {
3583
+ name: tableName
3584
+ };
3585
+ return baseSource('tileset', options, urlParameters);
3586
+ };
3587
+
3588
+ const vectorQuerySource = async function vectorQuerySource(options) {
3589
+ const {
3590
+ columns,
3591
+ filters,
3592
+ spatialDataColumn = DEFAULT_GEO_COLUMN,
3593
+ sqlQuery,
3594
+ tileResolution = DEFAULT_TILE_RESOLUTION,
3595
+ queryParameters,
3596
+ aggregationExp
3597
+ } = options;
3598
+ const spatialDataType = 'geo';
3599
+ const urlParameters = {
3600
+ spatialDataColumn,
3601
+ spatialDataType,
3602
+ tileResolution: tileResolution.toString(),
3603
+ q: sqlQuery
3604
+ };
3605
+ if (columns) {
3606
+ urlParameters.columns = columns.join(',');
3607
+ }
3608
+ if (filters) {
3609
+ urlParameters.filters = filters;
3610
+ }
3611
+ if (queryParameters) {
3612
+ urlParameters.queryParameters = queryParameters;
3613
+ }
3614
+ if (aggregationExp) {
3615
+ urlParameters.aggregationExp = aggregationExp;
3616
+ }
3617
+ return baseSource('query', options, urlParameters).then(result => _extends({}, result, {
3618
+ widgetSource: new WidgetQuerySource(_extends({}, options, {
3619
+ // NOTE: Parameters with default values above must be explicitly passed here.
3620
+ spatialDataColumn,
3621
+ spatialDataType,
3622
+ tileResolution
3623
+ }))
3624
+ }));
3625
+ };
3626
+
3627
+ const vectorTableSource = async function vectorTableSource(options) {
3628
+ const {
3629
+ columns,
3630
+ filters,
3631
+ spatialDataColumn = DEFAULT_GEO_COLUMN,
3632
+ tableName,
3633
+ tileResolution = DEFAULT_TILE_RESOLUTION,
3634
+ aggregationExp
3635
+ } = options;
3636
+ const spatialDataType = 'geo';
3637
+ const urlParameters = {
3638
+ name: tableName,
3639
+ spatialDataColumn,
3640
+ spatialDataType,
3641
+ tileResolution: tileResolution.toString()
3642
+ };
3643
+ if (columns) {
3644
+ urlParameters.columns = columns.join(',');
3645
+ }
3646
+ if (filters) {
3647
+ urlParameters.filters = filters;
3648
+ }
3649
+ if (aggregationExp) {
3650
+ urlParameters.aggregationExp = aggregationExp;
3651
+ }
3652
+ return baseSource('table', options, urlParameters).then(result => _extends({}, result, {
3653
+ widgetSource: new WidgetTableSource(_extends({}, options, {
3654
+ // NOTE: Parameters with default values above must be explicitly passed here.
3655
+ spatialDataColumn,
3656
+ spatialDataType,
3657
+ tileResolution
3658
+ }))
3659
+ }));
3660
+ };
3661
+
3662
+ // deck.gl
3663
+ // SPDX-License-Identifier: MIT
3664
+ // Copyright (c) vis.gl contributors
3665
+ const vectorTilesetSource = async function vectorTilesetSource(options) {
3666
+ const {
3667
+ tableName
3668
+ } = options;
3669
+ const urlParameters = {
3670
+ name: tableName
3671
+ };
3672
+ return baseSource('tileset', options, urlParameters);
3673
+ };
3674
+
3675
+ const query = async function query(options) {
3676
+ const {
3677
+ apiBaseUrl = SOURCE_DEFAULTS.apiBaseUrl,
3678
+ clientId = SOURCE_DEFAULTS.clientId,
3679
+ maxLengthURL = SOURCE_DEFAULTS.maxLengthURL,
3680
+ localCache,
3681
+ connectionName,
3682
+ sqlQuery,
3683
+ queryParameters
3684
+ } = options;
3685
+ const urlParameters = {
3686
+ q: sqlQuery
3687
+ };
3688
+ if (queryParameters) {
3689
+ urlParameters.queryParameters = JSON.stringify(queryParameters);
3690
+ }
3691
+ const baseUrl = buildQueryUrl({
3692
+ apiBaseUrl,
3693
+ connectionName
3694
+ });
3695
+ const headers = _extends({
3696
+ Authorization: `Bearer ${options.accessToken}`
3697
+ }, options.headers);
3698
+ const parameters = _extends({
3699
+ client: clientId
3700
+ }, urlParameters);
3701
+ const errorContext = {
3702
+ requestType: 'SQL',
3703
+ connection: options.connectionName,
3704
+ type: 'query',
3705
+ source: JSON.stringify(parameters, undefined, 2)
3706
+ };
3707
+ return await requestWithParameters({
3708
+ baseUrl,
3709
+ parameters,
3710
+ headers,
3711
+ errorContext,
3712
+ maxLengthURL,
3713
+ localCache
3714
+ });
3715
+ };
3716
+
3717
+ export { ApiVersion, CartoAPIError, DEFAULT_API_BASE_URL, FEATURE_GEOM_PROPERTY, FilterType, Provider, SOURCE_DEFAULTS, SpatialIndex, TileFormat, 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 };
3718
+ //# sourceMappingURL=api-client.modern.js.map