@carto/api-client 0.5.0-alpha.4 → 0.5.0-alpha.5

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