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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/CHANGELOG.md +17 -1
  2. package/build/api/carto-api-error.d.ts +1 -1
  3. package/build/api/query.d.ts +1 -1
  4. package/build/api/request-with-parameters.d.ts +2 -2
  5. package/build/api-client.cjs +2365 -279
  6. package/build/api-client.cjs.map +1 -1
  7. package/build/api-client.modern.js +2274 -298
  8. package/build/api-client.modern.js.map +1 -1
  9. package/build/client.d.ts +2 -2
  10. package/build/constants-internal.d.ts +5 -5
  11. package/build/constants.d.ts +25 -3
  12. package/build/deck/get-data-filter-extension-props.d.ts +28 -0
  13. package/build/deck/index.d.ts +1 -0
  14. package/build/filters/Filter.d.ts +25 -0
  15. package/build/filters/FilterTypes.d.ts +3 -0
  16. package/build/filters/geosjonFeatures.d.ts +8 -0
  17. package/build/filters/index.d.ts +6 -0
  18. package/build/filters/tileFeatures.d.ts +20 -0
  19. package/build/filters/tileFeaturesGeometries.d.ts +13 -0
  20. package/build/filters/tileFeaturesSpatialIndex.d.ts +10 -0
  21. package/build/filters.d.ts +2 -2
  22. package/build/geo.d.ts +1 -1
  23. package/build/index.d.ts +5 -0
  24. package/build/models/common.d.ts +5 -4
  25. package/build/models/index.d.ts +1 -1
  26. package/build/models/model.d.ts +2 -2
  27. package/build/operations/aggregation.d.ts +8 -0
  28. package/build/operations/applySorting.d.ts +20 -0
  29. package/build/operations/groupBy.d.ts +15 -0
  30. package/build/operations/groupByDate.d.ts +11 -0
  31. package/build/operations/histogram.d.ts +13 -0
  32. package/build/operations/index.d.ts +6 -0
  33. package/build/operations/scatterPlot.d.ts +14 -0
  34. package/build/sources/base-source.d.ts +2 -2
  35. package/build/sources/boundary-query-source.d.ts +1 -1
  36. package/build/sources/boundary-table-source.d.ts +1 -1
  37. package/build/sources/h3-query-source.d.ts +2 -2
  38. package/build/sources/h3-table-source.d.ts +2 -2
  39. package/build/sources/h3-tileset-source.d.ts +1 -1
  40. package/build/sources/index.d.ts +26 -26
  41. package/build/sources/quadbin-query-source.d.ts +2 -2
  42. package/build/sources/quadbin-table-source.d.ts +2 -2
  43. package/build/sources/quadbin-tileset-source.d.ts +1 -1
  44. package/build/sources/raster-source.d.ts +1 -1
  45. package/build/sources/types.d.ts +3 -3
  46. package/build/sources/vector-query-source.d.ts +1 -1
  47. package/build/sources/vector-table-source.d.ts +1 -1
  48. package/build/sources/vector-tileset-source.d.ts +1 -1
  49. package/build/spatial-index.d.ts +3 -3
  50. package/build/types-internal.d.ts +9 -5
  51. package/build/types.d.ts +74 -14
  52. package/build/utils/dateUtils.d.ts +10 -0
  53. package/build/utils/getTileFormat.d.ts +3 -0
  54. package/build/utils/makeIntervalComplete.d.ts +2 -0
  55. package/build/utils/transformTileCoordsToWGS84.d.ts +8 -0
  56. package/build/utils/transformToTileCoords.d.ts +9 -0
  57. package/build/utils.d.ts +3 -3
  58. package/build/widget-sources/index.d.ts +3 -1
  59. package/build/widget-sources/types.d.ts +38 -25
  60. package/build/widget-sources/widget-query-source.d.ts +4 -3
  61. package/build/widget-sources/widget-remote-source.d.ts +18 -0
  62. package/build/widget-sources/{widget-base-source.d.ts → widget-source.d.ts} +16 -41
  63. package/build/widget-sources/widget-table-source.d.ts +4 -3
  64. package/build/widget-sources/widget-tileset-source.d.ts +75 -0
  65. package/package.json +46 -29
  66. package/src/api/carto-api-error.ts +1 -1
  67. package/src/api/query.ts +5 -5
  68. package/src/api/request-with-parameters.ts +6 -6
  69. package/src/client.ts +3 -3
  70. package/src/constants-internal.ts +5 -5
  71. package/src/constants.ts +28 -3
  72. package/src/deck/get-data-filter-extension-props.ts +164 -0
  73. package/src/deck/index.ts +1 -0
  74. package/src/filters/Filter.ts +179 -0
  75. package/src/filters/FilterTypes.ts +109 -0
  76. package/src/filters/geosjonFeatures.ts +32 -0
  77. package/src/filters/index.ts +6 -0
  78. package/src/filters/tileFeatures.ts +50 -0
  79. package/src/filters/tileFeaturesGeometries.ts +444 -0
  80. package/src/filters/tileFeaturesSpatialIndex.ts +119 -0
  81. package/src/filters.ts +4 -4
  82. package/src/geo.ts +12 -14
  83. package/src/index.ts +7 -0
  84. package/src/models/common.ts +11 -9
  85. package/src/models/index.ts +1 -1
  86. package/src/models/model.ts +3 -4
  87. package/src/operations/aggregation.ts +154 -0
  88. package/src/operations/applySorting.ts +109 -0
  89. package/src/operations/groupBy.ts +59 -0
  90. package/src/operations/groupByDate.ts +98 -0
  91. package/src/operations/histogram.ts +66 -0
  92. package/src/operations/index.ts +6 -0
  93. package/src/operations/scatterPlot.ts +50 -0
  94. package/src/sources/base-source.ts +8 -8
  95. package/src/sources/boundary-query-source.ts +2 -2
  96. package/src/sources/boundary-table-source.ts +2 -2
  97. package/src/sources/h3-query-source.ts +7 -5
  98. package/src/sources/h3-table-source.ts +7 -5
  99. package/src/sources/h3-tileset-source.ts +2 -2
  100. package/src/sources/index.ts +26 -26
  101. package/src/sources/quadbin-query-source.ts +7 -5
  102. package/src/sources/quadbin-table-source.ts +7 -5
  103. package/src/sources/quadbin-tileset-source.ts +2 -2
  104. package/src/sources/raster-source.ts +3 -2
  105. package/src/sources/types.ts +3 -3
  106. package/src/sources/vector-query-source.ts +7 -5
  107. package/src/sources/vector-table-source.ts +7 -5
  108. package/src/sources/vector-tileset-source.ts +2 -2
  109. package/src/spatial-index.ts +4 -5
  110. package/src/types-internal.ts +11 -5
  111. package/src/types.ts +73 -15
  112. package/src/utils/dateUtils.ts +28 -0
  113. package/src/utils/getTileFormat.ts +9 -0
  114. package/src/utils/makeIntervalComplete.ts +17 -0
  115. package/src/utils/transformTileCoordsToWGS84.ts +77 -0
  116. package/src/utils/transformToTileCoords.ts +85 -0
  117. package/src/utils.ts +3 -3
  118. package/src/widget-sources/index.ts +3 -1
  119. package/src/widget-sources/types.ts +39 -25
  120. package/src/widget-sources/widget-query-source.ts +12 -5
  121. package/src/widget-sources/{widget-base-source.ts → widget-remote-source.ts} +51 -171
  122. package/src/widget-sources/widget-source.ts +173 -0
  123. package/src/widget-sources/widget-table-source.ts +12 -5
  124. package/src/widget-sources/widget-tileset-source.ts +456 -0
@@ -1,67 +1,1424 @@
1
- var bboxClip = require('@turf/bbox-clip');
1
+ var intersects = require('@turf/boolean-intersects');
2
2
  var bboxPolygon = require('@turf/bbox-polygon');
3
+ var booleanWithin = require('@turf/boolean-within');
4
+ var intersect = require('@turf/intersect');
5
+ var helpers = require('@turf/helpers');
6
+ var bboxClip = require('@turf/bbox-clip');
7
+ var h3Js = require('h3-js');
3
8
  var union = require('@turf/union');
4
9
  var invariant = require('@turf/invariant');
5
- var helpers = require('@turf/helpers');
10
+ var booleanEqual = require('@turf/boolean-equal');
6
11
 
7
12
  /**
8
13
  * @internal
9
- * @internalRemarks Source: @carto/react-core, @carto/constants, @deck.gl/carto
14
+ * @privateRemarks Source: @carto/react-core, @carto/constants, @deck.gl/carto
10
15
  */
11
16
  let client = 'deck-gl-carto';
12
17
  /**
13
18
  * Returns current client ID, used to categorize API requests. For internal use only.
14
19
  *
15
20
  * @internal
16
- * @internalRemarks Source: @carto/react-core
21
+ * @privateRemarks Source: @carto/react-core
17
22
  */
18
23
  function getClient() {
19
24
  return client;
20
25
  }
21
- /**
22
- * Sets current client ID, used to categorize API requests. For internal use only.
23
- *
24
- * @internal
25
- * @internalRemarks Source: @carto/react-core
26
- */
27
- function setClient(c) {
28
- client = c;
26
+ /**
27
+ * Sets current client ID, used to categorize API requests. For internal use only.
28
+ *
29
+ * @internal
30
+ * @privateRemarks Source: @carto/react-core
31
+ */
32
+ function setClient(c) {
33
+ client = c;
34
+ }
35
+
36
+ /**
37
+ * Defines a comparator used when matching a column's values against given filter values.
38
+ *
39
+ * Example:
40
+ *
41
+ * ```javascript
42
+ * import { FilterType } from '@carto/api-client';
43
+ * const filters = {
44
+ * column_name: { [FilterType.IN]: { values: ['a', 'b', 'c'] } }
45
+ * };
46
+ * ```
47
+ *
48
+ * @privateRemarks Source: @carto/react-api, @deck.gl/carto
49
+ */
50
+ exports.FilterType = void 0;
51
+ (function (FilterType) {
52
+ FilterType["IN"] = "in";
53
+ /** [a, b] both are included. */
54
+ FilterType["BETWEEN"] = "between";
55
+ /** [a, b) a is included, b is not. */
56
+ FilterType["CLOSED_OPEN"] = "closed_open";
57
+ FilterType["TIME"] = "time";
58
+ FilterType["STRING_SEARCH"] = "stringSearch";
59
+ })(exports.FilterType || (exports.FilterType = {}));
60
+ /** @privateRemarks Source: @carto/constants */
61
+ exports.ApiVersion = void 0;
62
+ (function (ApiVersion) {
63
+ ApiVersion["V1"] = "v1";
64
+ ApiVersion["V2"] = "v2";
65
+ ApiVersion["V3"] = "v3";
66
+ })(exports.ApiVersion || (exports.ApiVersion = {}));
67
+ /** @privateRemarks Source: @carto/constants, @deck.gl/carto */
68
+ const DEFAULT_API_BASE_URL = 'https://gcp-us-east1.api.carto.com';
69
+ /** @privateRemarks Source: @carto/react-core */
70
+ exports.TileFormat = void 0;
71
+ (function (TileFormat) {
72
+ TileFormat["MVT"] = "mvt";
73
+ TileFormat["JSON"] = "json";
74
+ TileFormat["GEOJSON"] = "geojson";
75
+ TileFormat["BINARY"] = "binary";
76
+ })(exports.TileFormat || (exports.TileFormat = {}));
77
+ /** @privateRemarks Source: @carto/react-core */
78
+ exports.SpatialIndex = void 0;
79
+ (function (SpatialIndex) {
80
+ SpatialIndex["H3"] = "h3";
81
+ SpatialIndex["S2"] = "s2";
82
+ SpatialIndex["QUADBIN"] = "quadbin";
83
+ })(exports.SpatialIndex || (exports.SpatialIndex = {}));
84
+ /** @privateRemarks Source: @carto/react-core */
85
+ exports.Provider = void 0;
86
+ (function (Provider) {
87
+ Provider["BIGQUERY"] = "bigquery";
88
+ Provider["REDSHIFT"] = "redshift";
89
+ Provider["POSTGRES"] = "postgres";
90
+ Provider["SNOWFLAKE"] = "snowflake";
91
+ Provider["DATABRICKS"] = "databricks";
92
+ Provider["DATABRICKS_REST"] = "databricksRest";
93
+ })(exports.Provider || (exports.Provider = {}));
94
+
95
+ function makeIntervalComplete(intervals) {
96
+ return intervals.map(val => {
97
+ if (val[0] === undefined || val[0] === null) {
98
+ return [Number.MIN_SAFE_INTEGER, val[1]];
99
+ }
100
+ if (val[1] === undefined || val[1] === null) {
101
+ return [val[0], Number.MAX_SAFE_INTEGER];
102
+ }
103
+ return val;
104
+ });
105
+ }
106
+
107
+ const filterFunctions = {
108
+ [exports.FilterType.IN]: filterIn,
109
+ [exports.FilterType.BETWEEN]: filterBetween,
110
+ [exports.FilterType.TIME]: filterTime,
111
+ [exports.FilterType.CLOSED_OPEN]: filterClosedOpen,
112
+ [exports.FilterType.STRING_SEARCH]: filterStringSearch
113
+ };
114
+ function filterIn(filterValues, featureValue) {
115
+ return filterValues.includes(featureValue);
116
+ }
117
+ // FilterTypes.BETWEEN
118
+ function filterBetween(filterValues, featureValue) {
119
+ const checkRange = range => {
120
+ const [lowerBound, upperBound] = range;
121
+ return featureValue >= lowerBound && featureValue <= upperBound;
122
+ };
123
+ return makeIntervalComplete(filterValues).some(checkRange);
124
+ }
125
+ function filterTime(filterValues, featureValue) {
126
+ const featureValueAsTimestamp = new Date(featureValue).getTime();
127
+ if (isFinite(featureValueAsTimestamp)) {
128
+ return filterBetween(filterValues, featureValueAsTimestamp);
129
+ } else {
130
+ throw new Error(`Column used to filter by time isn't well formatted.`);
131
+ }
132
+ }
133
+ // FilterTypes.CLOSED_OPEN
134
+ function filterClosedOpen(filterValues, featureValue) {
135
+ const checkRange = range => {
136
+ const [lowerBound, upperBound] = range;
137
+ return featureValue >= lowerBound && featureValue < upperBound;
138
+ };
139
+ return makeIntervalComplete(filterValues).some(checkRange);
140
+ }
141
+ // FilterTypes.STRING_SEARCH
142
+ function filterStringSearch(filterValues, featureValue, params) {
143
+ if (params === void 0) {
144
+ params = {};
145
+ }
146
+ const normalizedFeatureValue = normalize(featureValue, params);
147
+ const stringRegExp = params.useRegExp ? filterValues : filterValues.map(filterValue => {
148
+ let stringRegExp = escapeRegExp(normalize(filterValue, params));
149
+ if (params.mustStart) stringRegExp = `^${stringRegExp}`;
150
+ if (params.mustEnd) stringRegExp = `${stringRegExp}$`;
151
+ return stringRegExp;
152
+ });
153
+ const regex = new RegExp(stringRegExp.join('|'), params.caseSensitive ? 'g' : 'gi');
154
+ return !!normalizedFeatureValue.match(regex);
155
+ }
156
+ // Aux
157
+ const specialCharRegExp = /[.*+?^${}()|[\]\\]/g;
158
+ const normalizeRegExp = /\p{Diacritic}/gu;
159
+ function escapeRegExp(value) {
160
+ return value.replace(specialCharRegExp, '\\$&');
161
+ }
162
+ function normalize(data, params) {
163
+ let normalizedData = String(data);
164
+ if (!params.keepSpecialCharacters) normalizedData = normalizedData.normalize('NFD').replace(normalizeRegExp, '');
165
+ return normalizedData;
166
+ }
167
+
168
+ const LOGICAL_OPERATOR_METHODS = {
169
+ and: 'every',
170
+ or: 'some'
171
+ };
172
+ function passesFilter(columns, filters, feature, filtersLogicalOperator) {
173
+ const method = LOGICAL_OPERATOR_METHODS[filtersLogicalOperator];
174
+ return columns[method](column => {
175
+ const columnFilters = filters[column];
176
+ const columnFilterTypes = Object.keys(columnFilters);
177
+ if (!feature || feature[column] === null || feature[column] === undefined) {
178
+ return false;
179
+ }
180
+ return columnFilterTypes.every(filter => {
181
+ const filterFunction = filterFunctions[filter];
182
+ if (!filterFunction) {
183
+ throw new Error(`"${filter}" filter is not implemented.`);
184
+ }
185
+ return filterFunction(columnFilters[filter].values, feature[column], columnFilters[filter].params);
186
+ });
187
+ });
188
+ }
189
+ /**
190
+ * @internal
191
+ * @privateRemarks Exported for use in @deck.gl/carto's getDataFilterExtensionProps.
192
+ */
193
+ function _buildFeatureFilter(_ref) {
194
+ let {
195
+ filters = {},
196
+ type = 'boolean',
197
+ filtersLogicalOperator = 'and'
198
+ } = _ref;
199
+ const columns = Object.keys(filters);
200
+ if (!columns.length) {
201
+ return () => type === 'number' ? 1 : true;
202
+ }
203
+ return feature => {
204
+ const f = feature.properties || feature;
205
+ const featurePassesFilter = passesFilter(columns, filters, f, filtersLogicalOperator);
206
+ return type === 'number' ? Number(featurePassesFilter) : featurePassesFilter;
207
+ };
208
+ }
209
+ /**
210
+ * Apply certain filters to a collection of features.
211
+ * @internal
212
+ */
213
+ function applyFilters(features, filters, filtersLogicalOperator) {
214
+ return Object.keys(filters).length ? features.filter(_buildFeatureFilter({
215
+ filters,
216
+ filtersLogicalOperator
217
+ })) : features;
218
+ }
219
+ /**
220
+ * Binary.
221
+ * @internal
222
+ */
223
+ function buildBinaryFeatureFilter(_ref2) {
224
+ let {
225
+ filters = {}
226
+ } = _ref2;
227
+ const columns = Object.keys(filters);
228
+ if (!columns.length) {
229
+ return () => 1;
230
+ }
231
+ return (featureIdIdx, binaryData) => passesFilterUsingBinary(columns, filters, featureIdIdx, binaryData);
232
+ }
233
+ function getValueFromNumericProps(featureIdIdx, binaryData, _ref3) {
234
+ let {
235
+ column
236
+ } = _ref3;
237
+ return binaryData.numericProps?.[column]?.value[featureIdIdx];
238
+ }
239
+ function getValueFromProperties(featureIdIdx, binaryData, _ref4) {
240
+ let {
241
+ column
242
+ } = _ref4;
243
+ const propertyIdx = binaryData.featureIds.value[featureIdIdx];
244
+ return binaryData.properties[propertyIdx]?.[column];
245
+ }
246
+ const GET_VALUE_BY_BINARY_PROP = {
247
+ properties: getValueFromProperties,
248
+ numericProps: getValueFromNumericProps
249
+ };
250
+ function getBinaryPropertyByFilterValues(filterValues) {
251
+ return typeof filterValues.flat()[0] === 'string' ? 'properties' : 'numericProps';
252
+ }
253
+ function getFeatureValue(featureIdIdx, binaryData, filter) {
254
+ const {
255
+ column,
256
+ values
257
+ } = filter;
258
+ const binaryProp = getBinaryPropertyByFilterValues(values);
259
+ const getFeatureValueFn = GET_VALUE_BY_BINARY_PROP[binaryProp];
260
+ return getFeatureValueFn(featureIdIdx, binaryData, {
261
+ column
262
+ });
263
+ }
264
+ function passesFilterUsingBinary(columns, filters, featureIdIdx, binaryData) {
265
+ return columns.every(column => {
266
+ const columnFilters = filters[column];
267
+ return Object.entries(columnFilters).every(_ref5 => {
268
+ let [type, {
269
+ values
270
+ }] = _ref5;
271
+ const filterFn = filterFunctions[type];
272
+ if (!filterFn) {
273
+ throw new Error(`"${type}" filter is not implemented.`);
274
+ }
275
+ if (!values) return 0;
276
+ const featureValue = getFeatureValue(featureIdIdx, binaryData, {
277
+ type: type,
278
+ column,
279
+ values
280
+ });
281
+ if (featureValue === undefined || featureValue === null) return 0;
282
+ return filterFn(values, featureValue);
283
+ });
284
+ });
285
+ }
286
+
287
+ function geojsonFeatures(_ref) {
288
+ let {
289
+ geojson,
290
+ spatialFilter,
291
+ uniqueIdProperty
292
+ } = _ref;
293
+ let uniqueIdx = 0;
294
+ const map = new Map();
295
+ if (!spatialFilter) {
296
+ return [];
297
+ }
298
+ for (const feature of geojson.features) {
299
+ const uniqueId = uniqueIdProperty ? feature.properties[uniqueIdProperty] : ++uniqueIdx;
300
+ if (!map.has(uniqueId) && intersects(spatialFilter, feature)) {
301
+ map.set(uniqueId, feature.properties);
302
+ }
303
+ }
304
+ return Array.from(map.values());
305
+ }
306
+
307
+ // math.gl
308
+ // SPDX-License-Identifier: MIT
309
+ // Copyright (c) vis.gl contributors
310
+ const DEFAULT_CONFIG = {
311
+ EPSILON: 1e-12,
312
+ debug: false,
313
+ precision: 4,
314
+ printTypes: false,
315
+ printDegrees: false,
316
+ printRowMajor: true,
317
+ _cartographicRadians: false
318
+ };
319
+ // Configuration is truly global as of v3.6 to ensure single config even if multiple copies of math.gl
320
+ // Multiple copies of config can be quite tricky to debug...
321
+ globalThis.mathgl = globalThis.mathgl || {
322
+ config: {
323
+ ...DEFAULT_CONFIG
324
+ }
325
+ };
326
+ /**
327
+ * Check if value is an "array"
328
+ * Returns `true` if value is either an array or a typed array
329
+ * Note: returns `false` for `ArrayBuffer` and `DataView` instances
330
+ * @note isTypedArray and isNumericArray are often more useful in TypeScript
331
+ */
332
+ function isArray(value) {
333
+ return Array.isArray(value) || ArrayBuffer.isView(value) && !(value instanceof DataView);
334
+ }
335
+ function lerp(a, b, t) {
336
+ if (isArray(a)) {
337
+ return a.map((ai, i) => lerp(ai, b[i], t));
338
+ }
339
+ return t * b + (1 - t) * a;
340
+ }
341
+
342
+ // Replacement for the external assert method to reduce bundle size
343
+ // Note: We don't use the second "message" argument in calling code,
344
+ // so no need to support it here
345
+ function assert$1(condition, message) {
346
+ if (!condition) {
347
+ throw new Error(message || '@math.gl/web-mercator: assertion failed.');
348
+ }
349
+ }
350
+
351
+ // TODO - THE UTILITIES IN THIS FILE SHOULD BE IMPORTED FROM WEB-MERCATOR-VIEWPORT MODULE
352
+ // CONSTANTS
353
+ const PI = Math.PI;
354
+ const PI_4 = PI / 4;
355
+ const DEGREES_TO_RADIANS = PI / 180;
356
+ const RADIANS_TO_DEGREES = 180 / PI;
357
+ const TILE_SIZE = 512;
358
+ /**
359
+ * Project [lng,lat] on sphere onto [x,y] on 512*512 Mercator Zoom 0 tile.
360
+ * Performs the nonlinear part of the web mercator projection.
361
+ * Remaining projection is done with 4x4 matrices which also handles
362
+ * perspective.
363
+ *
364
+ * @param lngLat - [lng, lat] coordinates
365
+ * Specifies a point on the sphere to project onto the map.
366
+ * @return [x,y] coordinates.
367
+ */
368
+ function lngLatToWorld(lngLat) {
369
+ const [lng, lat] = lngLat;
370
+ assert$1(Number.isFinite(lng));
371
+ assert$1(Number.isFinite(lat) && lat >= -90 && lat <= 90, 'invalid latitude');
372
+ const lambda2 = lng * DEGREES_TO_RADIANS;
373
+ const phi2 = lat * DEGREES_TO_RADIANS;
374
+ const x = TILE_SIZE * (lambda2 + PI) / (2 * PI);
375
+ const y = TILE_SIZE * (PI + Math.log(Math.tan(PI_4 + phi2 * 0.5))) / (2 * PI);
376
+ return [x, y];
377
+ }
378
+ /**
379
+ * Unproject world point [x,y] on map onto {lat, lon} on sphere
380
+ *
381
+ * @param xy - array with [x,y] members
382
+ * representing point on projected map plane
383
+ * @return - array with [x,y] of point on sphere.
384
+ * Has toArray method if you need a GeoJSON Array.
385
+ * Per cartographic tradition, lat and lon are specified as degrees.
386
+ */
387
+ function worldToLngLat(xy) {
388
+ const [x, y] = xy;
389
+ const lambda2 = x / TILE_SIZE * (2 * PI) - PI;
390
+ const phi2 = 2 * (Math.atan(Math.exp(y / TILE_SIZE * (2 * PI) - PI)) - PI_4);
391
+ return [lambda2 * RADIANS_TO_DEGREES, phi2 * RADIANS_TO_DEGREES];
392
+ }
393
+
394
+ const TRANSFORM_FN$1 = {
395
+ Point: transformPoint$1,
396
+ MultiPoint: transformMultiPoint$1,
397
+ LineString: transformLineString$1,
398
+ MultiLineString: transformMultiLineString$1,
399
+ Polygon: transformPolygon$1,
400
+ MultiPolygon: transformMultiPolygon$1
401
+ };
402
+ /**
403
+ * Transform WGS84 coordinates to tile coords.
404
+ * 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)
405
+ *
406
+ * @param geometry - any valid geojson geometry
407
+ * @param bbox - geojson bbox
408
+ */
409
+ function transformToTileCoords(geometry, bbox) {
410
+ const [west, south, east, north] = bbox;
411
+ const nw = projectFlat([west, north]);
412
+ const se = projectFlat([east, south]);
413
+ const projectedBbox = [nw, se];
414
+ if (geometry.type === 'GeometryCollection') {
415
+ throw new Error('Unsupported geometry type GeometryCollection');
416
+ }
417
+ const transformFn = TRANSFORM_FN$1[geometry.type];
418
+ const coordinates = transformFn(geometry.coordinates, projectedBbox);
419
+ return {
420
+ ...geometry,
421
+ coordinates
422
+ };
423
+ }
424
+ function transformPoint$1(_ref, _ref2) {
425
+ let [pointX, pointY] = _ref;
426
+ let [nw, se] = _ref2;
427
+ const x = inverseLerp(nw[0], se[0], pointX);
428
+ const y = inverseLerp(nw[1], se[1], pointY);
429
+ return [x, y];
430
+ }
431
+ function getPoints$1(geometry, bbox) {
432
+ return geometry.map(g => transformPoint$1(projectFlat(g), bbox));
433
+ }
434
+ function transformMultiPoint$1(multiPoint, bbox) {
435
+ return getPoints$1(multiPoint, bbox);
436
+ }
437
+ function transformLineString$1(line, bbox) {
438
+ return getPoints$1(line, bbox);
439
+ }
440
+ function transformMultiLineString$1(multiLineString, bbox) {
441
+ return multiLineString.map(lineString => transformLineString$1(lineString, bbox));
442
+ }
443
+ function transformPolygon$1(polygon, bbox) {
444
+ return polygon.map(polygonRing => getPoints$1(polygonRing, bbox));
445
+ }
446
+ function transformMultiPolygon$1(multiPolygon, bbox) {
447
+ return multiPolygon.map(polygon => transformPolygon$1(polygon, bbox));
448
+ }
449
+ function projectFlat(xyz) {
450
+ return lngLatToWorld(xyz);
451
+ }
452
+ function inverseLerp(a, b, x) {
453
+ return (x - a) / (b - a);
454
+ }
455
+
456
+ const TRANSFORM_FN = {
457
+ Point: transformPoint,
458
+ MultiPoint: transformMultiPoint,
459
+ LineString: transformLineString,
460
+ MultiLineString: transformMultiLineString,
461
+ Polygon: transformPolygon,
462
+ MultiPolygon: transformMultiPolygon
463
+ };
464
+ /**
465
+ * Transform tile coords to WGS84 coordinates.
466
+ *
467
+ * @param geometry - any valid geojson geometry
468
+ * @param bbox - geojson bbox
469
+ */
470
+ function transformTileCoordsToWGS84(geometry, bbox) {
471
+ const [west, south, east, north] = bbox;
472
+ const nw = lngLatToWorld([west, north]);
473
+ const se = lngLatToWorld([east, south]);
474
+ const projectedBbox = [nw, se];
475
+ if (geometry.type === 'GeometryCollection') {
476
+ throw new Error('Unsupported geometry type GeometryCollection');
477
+ }
478
+ const transformFn = TRANSFORM_FN[geometry.type];
479
+ const coordinates = transformFn(geometry.coordinates, projectedBbox);
480
+ return {
481
+ ...geometry,
482
+ coordinates
483
+ };
484
+ }
485
+ function transformPoint(_ref, _ref2) {
486
+ let [pointX, pointY] = _ref;
487
+ let [nw, se] = _ref2;
488
+ const x = lerp(nw[0], se[0], pointX);
489
+ const y = lerp(nw[1], se[1], pointY);
490
+ return worldToLngLat([x, y]);
491
+ }
492
+ function getPoints(geometry, bbox) {
493
+ return geometry.map(g => transformPoint(g, bbox));
494
+ }
495
+ function transformMultiPoint(multiPoint, bbox) {
496
+ return getPoints(multiPoint, bbox);
497
+ }
498
+ function transformLineString(line, bbox) {
499
+ return getPoints(line, bbox);
500
+ }
501
+ function transformMultiLineString(multiLineString, bbox) {
502
+ return multiLineString.map(lineString => transformLineString(lineString, bbox));
503
+ }
504
+ function transformPolygon(polygon, bbox) {
505
+ return polygon.map(polygonRing => getPoints(polygonRing, bbox));
506
+ }
507
+ function transformMultiPolygon(multiPolygon, bbox) {
508
+ return multiPolygon.map(polygon => transformPolygon(polygon, bbox));
509
+ }
510
+
511
+ const FEATURE_GEOM_PROPERTY = '__geomValue';
512
+ function tileFeaturesGeometries(_ref) {
513
+ let {
514
+ tiles,
515
+ tileFormat,
516
+ spatialFilter,
517
+ uniqueIdProperty,
518
+ options
519
+ } = _ref;
520
+ const map = new Map();
521
+ for (const tile of tiles) {
522
+ // Discard if it's not a visible tile (only check false value, not undefined)
523
+ // or tile has not data
524
+ if (tile.isVisible === false || !tile.data) {
525
+ continue;
526
+ }
527
+ const bbox = [tile.bbox.west, tile.bbox.south, tile.bbox.east, tile.bbox.north];
528
+ const bboxToGeom = bboxPolygon(bbox);
529
+ const tileIsFullyVisible = booleanWithin(bboxToGeom, spatialFilter);
530
+ // Clip the geometry to intersect with the tile
531
+ const spatialFilterFeature = {
532
+ type: 'Feature',
533
+ geometry: spatialFilter,
534
+ properties: {}
535
+ };
536
+ const clippedGeometryToIntersect = intersect(helpers.featureCollection([bboxToGeom, spatialFilterFeature]));
537
+ if (!clippedGeometryToIntersect) {
538
+ continue;
539
+ }
540
+ // We assume that MVT tileFormat uses local coordinates so we transform the geometry to intersect to tile coordinates [0..1],
541
+ // while in the case of 'geojson' or binary, the geometries are already in WGS84
542
+ const transformedGeometryToIntersect = tileFormat === exports.TileFormat.MVT ? transformToTileCoords(clippedGeometryToIntersect.geometry, bbox) : clippedGeometryToIntersect.geometry;
543
+ createIndicesForPoints(tile.data.points);
544
+ calculateFeatures({
545
+ map,
546
+ tileIsFullyVisible,
547
+ geometryIntersection: transformedGeometryToIntersect,
548
+ data: tile.data.points,
549
+ type: 'Point',
550
+ bbox,
551
+ tileFormat,
552
+ uniqueIdProperty,
553
+ options
554
+ });
555
+ calculateFeatures({
556
+ map,
557
+ tileIsFullyVisible,
558
+ geometryIntersection: transformedGeometryToIntersect,
559
+ data: tile.data.lines,
560
+ type: 'LineString',
561
+ bbox,
562
+ tileFormat,
563
+ uniqueIdProperty,
564
+ options
565
+ });
566
+ calculateFeatures({
567
+ map,
568
+ tileIsFullyVisible,
569
+ geometryIntersection: transformedGeometryToIntersect,
570
+ data: tile.data.polygons,
571
+ type: 'Polygon',
572
+ bbox,
573
+ tileFormat,
574
+ uniqueIdProperty,
575
+ options
576
+ });
577
+ }
578
+ return Array.from(map.values());
579
+ }
580
+ function processTileFeatureProperties(_ref2) {
581
+ let {
582
+ map,
583
+ data,
584
+ startIndex,
585
+ endIndex,
586
+ type,
587
+ bbox,
588
+ tileFormat,
589
+ uniqueIdProperty,
590
+ storeGeometry,
591
+ geometryIntersection
592
+ } = _ref2;
593
+ const tileProps = getPropertiesFromTile(data, startIndex);
594
+ const uniquePropertyValue = getUniquePropertyValue(tileProps, uniqueIdProperty, map);
595
+ if (!uniquePropertyValue || map.has(uniquePropertyValue)) {
596
+ return;
597
+ }
598
+ let geometry = null;
599
+ // Only calculate geometry if necessary
600
+ if (storeGeometry || geometryIntersection) {
601
+ const {
602
+ positions
603
+ } = data;
604
+ const ringCoordinates = getRingCoordinatesFor(startIndex, endIndex, positions);
605
+ geometry = getFeatureByType(ringCoordinates, type);
606
+ }
607
+ // If intersection is required, check before proceeding
608
+ if (geometry && geometryIntersection && !intersects(geometry, geometryIntersection)) {
609
+ return;
610
+ }
611
+ const properties = parseProperties(tileProps);
612
+ // Only save geometry if necessary
613
+ if (storeGeometry && geometry) {
614
+ properties[FEATURE_GEOM_PROPERTY] = tileFormat === exports.TileFormat.MVT ? transformTileCoordsToWGS84(geometry, bbox) : geometry;
615
+ }
616
+ map.set(uniquePropertyValue, properties);
617
+ }
618
+ function addIntersectedFeaturesInTile(_ref3) {
619
+ let {
620
+ map,
621
+ data,
622
+ geometryIntersection,
623
+ type,
624
+ bbox,
625
+ tileFormat,
626
+ uniqueIdProperty,
627
+ options
628
+ } = _ref3;
629
+ const indices = getIndices(data);
630
+ const storeGeometry = options?.storeGeometry || false;
631
+ for (let i = 0; i < indices.length - 1; i++) {
632
+ const startIndex = indices[i];
633
+ const endIndex = indices[i + 1];
634
+ processTileFeatureProperties({
635
+ map,
636
+ data,
637
+ startIndex,
638
+ endIndex,
639
+ type,
640
+ bbox,
641
+ tileFormat,
642
+ uniqueIdProperty,
643
+ storeGeometry,
644
+ geometryIntersection
645
+ });
646
+ }
647
+ }
648
+ function getIndices(data) {
649
+ let indices;
650
+ switch (data.type) {
651
+ case 'Point':
652
+ // @ts-expect-error Missing or changed types?
653
+ indices = data.pointIndices;
654
+ break;
655
+ case 'LineString':
656
+ indices = data.pathIndices;
657
+ break;
658
+ case 'Polygon':
659
+ indices = data.primitivePolygonIndices;
660
+ break;
661
+ default:
662
+ throw new Error(`Unexpected type, "${data.type}"`);
663
+ }
664
+ return indices.value;
665
+ }
666
+ function getFeatureId(data, startIndex) {
667
+ return data.featureIds.value[startIndex];
668
+ }
669
+ function getPropertiesFromTile(data, startIndex) {
670
+ const featureId = getFeatureId(data, startIndex);
671
+ const {
672
+ properties,
673
+ numericProps,
674
+ fields
675
+ } = data;
676
+ const result = {
677
+ uniqueId: fields?.[featureId]?.id,
678
+ properties: properties[featureId],
679
+ numericProps: {}
680
+ };
681
+ for (const key in numericProps) {
682
+ result.numericProps[key] = numericProps[key].value[startIndex];
683
+ }
684
+ return result;
685
+ }
686
+ function parseProperties(tileProps) {
687
+ const {
688
+ properties,
689
+ numericProps
690
+ } = tileProps;
691
+ return Object.assign({}, properties, numericProps);
692
+ }
693
+ function getUniquePropertyValue(tileProps, uniqueIdProperty, map) {
694
+ if (uniqueIdProperty) {
695
+ return getValueFromTileProps(tileProps, uniqueIdProperty);
696
+ }
697
+ if (tileProps.uniqueId) {
698
+ return tileProps.uniqueId;
699
+ }
700
+ const artificialId = map.size + 1; // a counter, assumed as a valid new id
701
+ return getValueFromTileProps(tileProps, 'cartodb_id') || getValueFromTileProps(tileProps, 'geoid') || artificialId;
702
+ }
703
+ function getValueFromTileProps(tileProps, propertyName) {
704
+ const {
705
+ properties,
706
+ numericProps
707
+ } = tileProps;
708
+ return numericProps[propertyName] || properties[propertyName];
709
+ }
710
+ function getFeatureByType(coordinates, type) {
711
+ switch (type) {
712
+ case 'Polygon':
713
+ return {
714
+ type: 'Polygon',
715
+ coordinates: [coordinates]
716
+ };
717
+ case 'LineString':
718
+ return {
719
+ type: 'LineString',
720
+ coordinates
721
+ };
722
+ case 'Point':
723
+ return {
724
+ type: 'Point',
725
+ coordinates: coordinates[0]
726
+ };
727
+ default:
728
+ throw new Error('Invalid geometry type');
729
+ }
730
+ }
731
+ function getRingCoordinatesFor(startIndex, endIndex, positions) {
732
+ const ringCoordinates = [];
733
+ for (let j = startIndex; j < endIndex; j++) {
734
+ ringCoordinates.push(Array.from(positions.value.subarray(j * positions.size, (j + 1) * positions.size)));
735
+ }
736
+ return ringCoordinates;
737
+ }
738
+ function calculateFeatures(_ref4) {
739
+ let {
740
+ map,
741
+ tileIsFullyVisible,
742
+ geometryIntersection,
743
+ data,
744
+ type,
745
+ bbox,
746
+ tileFormat,
747
+ uniqueIdProperty,
748
+ options
749
+ } = _ref4;
750
+ if (!data?.properties.length) {
751
+ return;
752
+ }
753
+ if (tileIsFullyVisible) {
754
+ addAllFeaturesInTile({
755
+ map,
756
+ data,
757
+ type,
758
+ bbox,
759
+ tileFormat,
760
+ uniqueIdProperty,
761
+ options
762
+ });
763
+ } else {
764
+ addIntersectedFeaturesInTile({
765
+ map,
766
+ data,
767
+ geometryIntersection,
768
+ type,
769
+ bbox,
770
+ tileFormat,
771
+ uniqueIdProperty,
772
+ options
773
+ });
774
+ }
775
+ }
776
+ function addAllFeaturesInTile(_ref5) {
777
+ let {
778
+ map,
779
+ data,
780
+ type,
781
+ bbox,
782
+ tileFormat,
783
+ uniqueIdProperty,
784
+ options
785
+ } = _ref5;
786
+ const indices = getIndices(data);
787
+ const storeGeometry = options?.storeGeometry || false;
788
+ for (let i = 0; i < indices.length - 1; i++) {
789
+ const startIndex = indices[i];
790
+ const endIndex = indices[i + 1];
791
+ processTileFeatureProperties({
792
+ map,
793
+ data,
794
+ startIndex,
795
+ endIndex,
796
+ type,
797
+ bbox,
798
+ tileFormat,
799
+ uniqueIdProperty,
800
+ storeGeometry
801
+ });
802
+ }
803
+ }
804
+ function createIndicesForPoints(data) {
805
+ const featureIds = data.featureIds.value;
806
+ const lastFeatureId = featureIds[featureIds.length - 1];
807
+ const PointIndicesArray = featureIds.constructor;
808
+ const pointIndices = {
809
+ value: new PointIndicesArray(featureIds.length + 1),
810
+ size: 1
811
+ };
812
+ pointIndices.value.set(featureIds);
813
+ pointIndices.value.set([lastFeatureId + 1], featureIds.length);
814
+ // @ts-expect-error Missing or changed types?
815
+ data.pointIndices = pointIndices;
816
+ }
817
+
818
+ // a tile is an array [x,y,z]
819
+ var d2r = Math.PI / 180,
820
+ r2d = 180 / Math.PI;
821
+ function tileToBBOX(tile) {
822
+ var e = tile2lon(tile[0] + 1, tile[2]);
823
+ var w = tile2lon(tile[0], tile[2]);
824
+ var s = tile2lat(tile[1] + 1, tile[2]);
825
+ var n = tile2lat(tile[1], tile[2]);
826
+ return [w, s, e, n];
827
+ }
828
+ function tileToGeoJSON(tile) {
829
+ var bbox = tileToBBOX(tile);
830
+ var poly = {
831
+ type: 'Polygon',
832
+ coordinates: [[[bbox[0], bbox[1]], [bbox[0], bbox[3]], [bbox[2], bbox[3]], [bbox[2], bbox[1]], [bbox[0], bbox[1]]]]
833
+ };
834
+ return poly;
835
+ }
836
+ function tile2lon(x, z) {
837
+ return x / Math.pow(2, z) * 360 - 180;
838
+ }
839
+ function tile2lat(y, z) {
840
+ var n = Math.PI - 2 * Math.PI * y / Math.pow(2, z);
841
+ return r2d * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)));
842
+ }
843
+ function pointToTile(lon, lat, z) {
844
+ var tile = pointToTileFraction(lon, lat, z);
845
+ tile[0] = Math.floor(tile[0]);
846
+ tile[1] = Math.floor(tile[1]);
847
+ return tile;
848
+ }
849
+ function getChildren(tile) {
850
+ return [[tile[0] * 2, tile[1] * 2, tile[2] + 1], [tile[0] * 2 + 1, tile[1] * 2, tile[2] + 1], [tile[0] * 2 + 1, tile[1] * 2 + 1, tile[2] + 1], [tile[0] * 2, tile[1] * 2 + 1, tile[2] + 1]];
851
+ }
852
+ function getParent(tile) {
853
+ // top left
854
+ if (tile[0] % 2 === 0 && tile[1] % 2 === 0) {
855
+ return [tile[0] / 2, tile[1] / 2, tile[2] - 1];
856
+ }
857
+ // bottom left
858
+ else if (tile[0] % 2 === 0 && !tile[1] % 2 === 0) {
859
+ return [tile[0] / 2, (tile[1] - 1) / 2, tile[2] - 1];
860
+ }
861
+ // top right
862
+ else if (!tile[0] % 2 === 0 && tile[1] % 2 === 0) {
863
+ return [(tile[0] - 1) / 2, tile[1] / 2, tile[2] - 1];
864
+ }
865
+ // bottom right
866
+ else {
867
+ return [(tile[0] - 1) / 2, (tile[1] - 1) / 2, tile[2] - 1];
868
+ }
869
+ }
870
+ function getSiblings(tile) {
871
+ return getChildren(getParent(tile));
872
+ }
873
+ function hasSiblings(tile, tiles) {
874
+ var siblings = getSiblings(tile);
875
+ for (var i = 0; i < siblings.length; i++) {
876
+ if (!hasTile(tiles, siblings[i])) return false;
877
+ }
878
+ return true;
879
+ }
880
+ function hasTile(tiles, tile) {
881
+ for (var i = 0; i < tiles.length; i++) {
882
+ if (tilesEqual(tiles[i], tile)) return true;
883
+ }
884
+ return false;
885
+ }
886
+ function tilesEqual(tile1, tile2) {
887
+ return tile1[0] === tile2[0] && tile1[1] === tile2[1] && tile1[2] === tile2[2];
888
+ }
889
+ function tileToQuadkey(tile) {
890
+ var index = '';
891
+ for (var z = tile[2]; z > 0; z--) {
892
+ var b = 0;
893
+ var mask = 1 << z - 1;
894
+ if ((tile[0] & mask) !== 0) b++;
895
+ if ((tile[1] & mask) !== 0) b += 2;
896
+ index += b.toString();
897
+ }
898
+ return index;
899
+ }
900
+ function quadkeyToTile(quadkey) {
901
+ var x = 0;
902
+ var y = 0;
903
+ var z = quadkey.length;
904
+ for (var i = z; i > 0; i--) {
905
+ var mask = 1 << i - 1;
906
+ switch (quadkey[z - i]) {
907
+ case '0':
908
+ break;
909
+ case '1':
910
+ x |= mask;
911
+ break;
912
+ case '2':
913
+ y |= mask;
914
+ break;
915
+ case '3':
916
+ x |= mask;
917
+ y |= mask;
918
+ break;
919
+ }
920
+ }
921
+ return [x, y, z];
922
+ }
923
+ function bboxToTile(bboxCoords) {
924
+ var min = pointToTile(bboxCoords[0], bboxCoords[1], 32);
925
+ var max = pointToTile(bboxCoords[2], bboxCoords[3], 32);
926
+ var bbox = [min[0], min[1], max[0], max[1]];
927
+ var z = getBboxZoom(bbox);
928
+ if (z === 0) return [0, 0, 0];
929
+ var x = bbox[0] >>> 32 - z;
930
+ var y = bbox[1] >>> 32 - z;
931
+ return [x, y, z];
932
+ }
933
+ function getBboxZoom(bbox) {
934
+ var MAX_ZOOM = 28;
935
+ for (var z = 0; z < MAX_ZOOM; z++) {
936
+ var mask = 1 << 32 - (z + 1);
937
+ if ((bbox[0] & mask) != (bbox[2] & mask) || (bbox[1] & mask) != (bbox[3] & mask)) {
938
+ return z;
939
+ }
940
+ }
941
+ return MAX_ZOOM;
942
+ }
943
+ function pointToTileFraction(lon, lat, z) {
944
+ var sin = Math.sin(lat * d2r),
945
+ z2 = Math.pow(2, z),
946
+ x = z2 * (lon / 360 + 0.5),
947
+ y = z2 * (0.5 - 0.25 * Math.log((1 + sin) / (1 - sin)) / Math.PI);
948
+ return [x, y, z];
949
+ }
950
+ var tilebelt = {
951
+ tileToGeoJSON: tileToGeoJSON,
952
+ tileToBBOX: tileToBBOX,
953
+ getChildren: getChildren,
954
+ getParent: getParent,
955
+ getSiblings: getSiblings,
956
+ hasTile: hasTile,
957
+ hasSiblings: hasSiblings,
958
+ tilesEqual: tilesEqual,
959
+ tileToQuadkey: tileToQuadkey,
960
+ quadkeyToTile: quadkeyToTile,
961
+ pointToTile: pointToTile,
962
+ bboxToTile: bboxToTile,
963
+ pointToTileFraction: pointToTileFraction
964
+ };
965
+
966
+ /**
967
+ * Given a geometry, create cells and return them in their raw form,
968
+ * as an array of cell identifiers.
969
+ *
970
+ * @alias tiles
971
+ * @param {Object} geom GeoJSON geometry
972
+ * @param {Object} limits an object with min_zoom and max_zoom properties
973
+ * specifying the minimum and maximum level to be tiled.
974
+ * @returns {Array<Array<number>>} An array of tiles given as [x, y, z] arrays
975
+ */
976
+ var tiles = getTiles;
977
+ function getTiles(geom, limits) {
978
+ var i,
979
+ tile,
980
+ coords = geom.coordinates,
981
+ maxZoom = limits.max_zoom,
982
+ tileHash = {},
983
+ tiles = [];
984
+ if (geom.type === 'Point') {
985
+ return [tilebelt.pointToTile(coords[0], coords[1], maxZoom)];
986
+ } else if (geom.type === 'MultiPoint') {
987
+ for (i = 0; i < coords.length; i++) {
988
+ tile = tilebelt.pointToTile(coords[i][0], coords[i][1], maxZoom);
989
+ tileHash[toID(tile[0], tile[1], tile[2])] = true;
990
+ }
991
+ } else if (geom.type === 'LineString') {
992
+ lineCover(tileHash, coords, maxZoom);
993
+ } else if (geom.type === 'MultiLineString') {
994
+ for (i = 0; i < coords.length; i++) {
995
+ lineCover(tileHash, coords[i], maxZoom);
996
+ }
997
+ } else if (geom.type === 'Polygon') {
998
+ polygonCover(tileHash, tiles, coords, maxZoom);
999
+ } else if (geom.type === 'MultiPolygon') {
1000
+ for (i = 0; i < coords.length; i++) {
1001
+ polygonCover(tileHash, tiles, coords[i], maxZoom);
1002
+ }
1003
+ } else {
1004
+ throw new Error('Geometry type not implemented');
1005
+ }
1006
+ if (limits.min_zoom !== maxZoom) {
1007
+ // sync tile hash and tile array so that both contain the same tiles
1008
+ var len = tiles.length;
1009
+ appendHashTiles(tileHash, tiles);
1010
+ for (i = 0; i < len; i++) {
1011
+ var t = tiles[i];
1012
+ tileHash[toID(t[0], t[1], t[2])] = true;
1013
+ }
1014
+ return mergeTiles(tileHash, tiles, limits);
1015
+ }
1016
+ appendHashTiles(tileHash, tiles);
1017
+ return tiles;
1018
+ }
1019
+ function mergeTiles(tileHash, tiles, limits) {
1020
+ var mergedTiles = [];
1021
+ for (var z = limits.max_zoom; z > limits.min_zoom; z--) {
1022
+ var parentTileHash = {};
1023
+ var parentTiles = [];
1024
+ for (var i = 0; i < tiles.length; i++) {
1025
+ var t = tiles[i];
1026
+ if (t[0] % 2 === 0 && t[1] % 2 === 0) {
1027
+ var id2 = toID(t[0] + 1, t[1], z),
1028
+ id3 = toID(t[0], t[1] + 1, z),
1029
+ id4 = toID(t[0] + 1, t[1] + 1, z);
1030
+ if (tileHash[id2] && tileHash[id3] && tileHash[id4]) {
1031
+ tileHash[toID(t[0], t[1], t[2])] = false;
1032
+ tileHash[id2] = false;
1033
+ tileHash[id3] = false;
1034
+ tileHash[id4] = false;
1035
+ var parentTile = [t[0] / 2, t[1] / 2, z - 1];
1036
+ if (z - 1 === limits.min_zoom) mergedTiles.push(parentTile);else {
1037
+ parentTileHash[toID(t[0] / 2, t[1] / 2, z - 1)] = true;
1038
+ parentTiles.push(parentTile);
1039
+ }
1040
+ }
1041
+ }
1042
+ }
1043
+ for (i = 0; i < tiles.length; i++) {
1044
+ t = tiles[i];
1045
+ if (tileHash[toID(t[0], t[1], t[2])]) mergedTiles.push(t);
1046
+ }
1047
+ tileHash = parentTileHash;
1048
+ tiles = parentTiles;
1049
+ }
1050
+ return mergedTiles;
1051
+ }
1052
+ function polygonCover(tileHash, tileArray, geom, zoom) {
1053
+ var intersections = [];
1054
+ for (var i = 0; i < geom.length; i++) {
1055
+ var ring = [];
1056
+ lineCover(tileHash, geom[i], zoom, ring);
1057
+ for (var j = 0, len = ring.length, k = len - 1; j < len; k = j++) {
1058
+ var m = (j + 1) % len;
1059
+ var y = ring[j][1];
1060
+
1061
+ // add interesction if it's not local extremum or duplicate
1062
+ if ((y > ring[k][1] || y > ring[m][1]) && (
1063
+ // not local minimum
1064
+ y < ring[k][1] || y < ring[m][1]) &&
1065
+ // not local maximum
1066
+ y !== ring[m][1]) intersections.push(ring[j]);
1067
+ }
1068
+ }
1069
+ intersections.sort(compareTiles); // sort by y, then x
1070
+
1071
+ for (i = 0; i < intersections.length; i += 2) {
1072
+ // fill tiles between pairs of intersections
1073
+ y = intersections[i][1];
1074
+ for (var x = intersections[i][0] + 1; x < intersections[i + 1][0]; x++) {
1075
+ var id = toID(x, y, zoom);
1076
+ if (!tileHash[id]) {
1077
+ tileArray.push([x, y, zoom]);
1078
+ }
1079
+ }
1080
+ }
1081
+ }
1082
+ function compareTiles(a, b) {
1083
+ return a[1] - b[1] || a[0] - b[0];
1084
+ }
1085
+ function lineCover(tileHash, coords, maxZoom, ring) {
1086
+ var prevX, prevY;
1087
+ for (var i = 0; i < coords.length - 1; i++) {
1088
+ var start = tilebelt.pointToTileFraction(coords[i][0], coords[i][1], maxZoom),
1089
+ stop = tilebelt.pointToTileFraction(coords[i + 1][0], coords[i + 1][1], maxZoom),
1090
+ x0 = start[0],
1091
+ y0 = start[1],
1092
+ x1 = stop[0],
1093
+ y1 = stop[1],
1094
+ dx = x1 - x0,
1095
+ dy = y1 - y0;
1096
+ if (dy === 0 && dx === 0) continue;
1097
+ var sx = dx > 0 ? 1 : -1,
1098
+ sy = dy > 0 ? 1 : -1,
1099
+ x = Math.floor(x0),
1100
+ y = Math.floor(y0),
1101
+ tMaxX = dx === 0 ? Infinity : Math.abs(((dx > 0 ? 1 : 0) + x - x0) / dx),
1102
+ tMaxY = dy === 0 ? Infinity : Math.abs(((dy > 0 ? 1 : 0) + y - y0) / dy),
1103
+ tdx = Math.abs(sx / dx),
1104
+ tdy = Math.abs(sy / dy);
1105
+ if (x !== prevX || y !== prevY) {
1106
+ tileHash[toID(x, y, maxZoom)] = true;
1107
+ if (ring && y !== prevY) ring.push([x, y]);
1108
+ prevX = x;
1109
+ prevY = y;
1110
+ }
1111
+ while (tMaxX < 1 || tMaxY < 1) {
1112
+ if (tMaxX < tMaxY) {
1113
+ tMaxX += tdx;
1114
+ x += sx;
1115
+ } else {
1116
+ tMaxY += tdy;
1117
+ y += sy;
1118
+ }
1119
+ tileHash[toID(x, y, maxZoom)] = true;
1120
+ if (ring && y !== prevY) ring.push([x, y]);
1121
+ prevX = x;
1122
+ prevY = y;
1123
+ }
1124
+ }
1125
+ if (ring && y === ring[0][1]) ring.pop();
1126
+ }
1127
+ function appendHashTiles(hash, tiles) {
1128
+ var keys = Object.keys(hash);
1129
+ for (var i = 0; i < keys.length; i++) {
1130
+ tiles.push(fromID(+keys[i]));
1131
+ }
1132
+ }
1133
+ function toID(x, y, z) {
1134
+ var dim = 2 * (1 << z);
1135
+ return (dim * y + x) * 32 + z;
1136
+ }
1137
+ function fromID(id) {
1138
+ var z = id % 32,
1139
+ dim = 2 * (1 << z),
1140
+ xy = (id - z) / 32,
1141
+ x = xy % dim,
1142
+ y = (xy - x) / dim % dim;
1143
+ return [x, y, z];
1144
+ }
1145
+
1146
+ const B = [0x5555555555555555n, 0x3333333333333333n, 0x0f0f0f0f0f0f0f0fn, 0x00ff00ff00ff00ffn, 0x0000ffff0000ffffn, 0x00000000ffffffffn];
1147
+ const S = [0n, 1n, 2n, 4n, 8n, 16n];
1148
+ function tileToCell(tile) {
1149
+ if (tile.z < 0 || tile.z > 26) {
1150
+ throw new Error('Wrong zoom');
1151
+ }
1152
+ const z = BigInt(tile.z);
1153
+ let x = BigInt(tile.x) << 32n - z;
1154
+ let y = BigInt(tile.y) << 32n - z;
1155
+ for (let i = 0; i < 5; i++) {
1156
+ const s = S[5 - i];
1157
+ const b = B[4 - i];
1158
+ x = (x | x << s) & b;
1159
+ y = (y | y << s) & b;
1160
+ }
1161
+ const quadbin = 0x4000000000000000n | 1n << 59n |
1162
+ // | (mode << 59) | (mode_dep << 57)
1163
+ z << 52n | (x | y << 1n) >> 12n | 0xfffffffffffffn >> z * 2n;
1164
+ return quadbin;
1165
+ }
1166
+ function getResolution$1(quadbin) {
1167
+ return quadbin >> 52n & 0x1fn;
1168
+ }
1169
+ function geometryToCells(geometry, resolution) {
1170
+ const zoom = Number(resolution);
1171
+ return tiles(geometry, {
1172
+ min_zoom: zoom,
1173
+ max_zoom: zoom
1174
+ }).map(([x, y, z]) => tileToCell({
1175
+ x,
1176
+ y,
1177
+ z
1178
+ }));
1179
+ }
1180
+
1181
+ function tileFeaturesSpatialIndex(_ref) {
1182
+ let {
1183
+ tiles,
1184
+ spatialFilter,
1185
+ spatialDataColumn,
1186
+ spatialDataType
1187
+ } = _ref;
1188
+ const map = new Map();
1189
+ const spatialIndex = getSpatialIndex(spatialDataType);
1190
+ const resolution = getResolution(tiles, spatialIndex);
1191
+ const spatialIndexIDName = spatialDataColumn ? spatialDataColumn : spatialIndex;
1192
+ if (!resolution) {
1193
+ return [];
1194
+ }
1195
+ const cells = getCellsCoverGeometry(spatialFilter, spatialIndex, resolution);
1196
+ if (!cells?.length) {
1197
+ return [];
1198
+ }
1199
+ // We transform cells to Set to improve the performace
1200
+ const cellsSet = new Set(cells);
1201
+ for (const tile of tiles) {
1202
+ if (tile.isVisible === false || !tile.data) {
1203
+ continue;
1204
+ }
1205
+ tile.data.forEach(d => {
1206
+ if (cellsSet.has(d.id)) {
1207
+ map.set(d.id, {
1208
+ ...d.properties,
1209
+ [spatialIndexIDName]: d.id
1210
+ });
1211
+ }
1212
+ });
1213
+ }
1214
+ return Array.from(map.values());
1215
+ }
1216
+ function getResolution(tiles, spatialIndex) {
1217
+ const data = tiles.find(tile => tile.data?.length)?.data;
1218
+ if (!data) {
1219
+ return;
1220
+ }
1221
+ if (spatialIndex === exports.SpatialIndex.QUADBIN) {
1222
+ return Number(getResolution$1(data[0].id));
1223
+ }
1224
+ if (spatialIndex === exports.SpatialIndex.H3) {
1225
+ return h3Js.getResolution(data[0].id);
1226
+ }
1227
+ }
1228
+ const bboxWest = [-180, -90, 0, 90];
1229
+ const bboxEast = [0, -90, 180, 90];
1230
+ function getCellsCoverGeometry(geometry, spatialIndex, resolution) {
1231
+ if (spatialIndex === exports.SpatialIndex.QUADBIN) {
1232
+ // @ts-expect-error TODO: Probably ought to be stricter about number vs. bigint types in this file.
1233
+ return geometryToCells(geometry, resolution);
1234
+ }
1235
+ if (spatialIndex === exports.SpatialIndex.H3) {
1236
+ // The current H3 polyfill algorithm can't deal with polygon segments of greater than 180 degrees longitude
1237
+ // so we clip the geometry to be sure that none of them is greater than 180 degrees
1238
+ // https://github.com/uber/h3-js/issues/24#issuecomment-431893796
1239
+ return h3Js.polygonToCells(bboxClip(geometry, bboxWest).geometry.coordinates, resolution, true).concat(h3Js.polygonToCells(bboxClip(geometry, bboxEast).geometry.coordinates, resolution, true));
1240
+ }
1241
+ }
1242
+ function getSpatialIndex(spatialDataType) {
1243
+ switch (spatialDataType) {
1244
+ case 'h3':
1245
+ return exports.SpatialIndex.H3;
1246
+ case 'quadbin':
1247
+ return exports.SpatialIndex.QUADBIN;
1248
+ default:
1249
+ throw new Error('Unexpected spatial data type');
1250
+ }
1251
+ }
1252
+
1253
+ /**
1254
+ * Current version of @carto/api-client.
1255
+ * @internal
1256
+ */
1257
+ /** @internal */
1258
+ const V3_MINOR_VERSION = '3.4';
1259
+ /** @privateRemarks Source: @carto/constants, @deck.gl/carto */
1260
+ const DEFAULT_GEO_COLUMN = 'geom';
1261
+ /**
1262
+ * Fastly default limit is 8192; leave some padding.
1263
+ * @privateRemarks Source: @deck.gl/carto
1264
+ */
1265
+ const DEFAULT_MAX_LENGTH_URL = 7000;
1266
+ /** @privateRemarks Source: @deck.gl/carto */
1267
+ const DEFAULT_TILE_RESOLUTION = 0.5;
1268
+ /**
1269
+ * @privateRemarks Source: @deck.gl/carto
1270
+ * @internal
1271
+ */
1272
+ const DEFAULT_AGGREGATION_RES_LEVEL_H3 = 4;
1273
+ /**
1274
+ * @privateRemarks Source: @deck.gl/carto
1275
+ * @internal
1276
+ */
1277
+ const DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN = 6;
1278
+
1279
+ /** @privateRemarks Source: @carto/react-core */
1280
+ function tileFeatures(_ref) {
1281
+ let {
1282
+ tiles,
1283
+ spatialFilter,
1284
+ uniqueIdProperty,
1285
+ tileFormat,
1286
+ spatialDataColumn = DEFAULT_GEO_COLUMN,
1287
+ spatialDataType,
1288
+ options = {}
1289
+ } = _ref;
1290
+ if (spatialDataType !== 'geo') {
1291
+ return tileFeaturesSpatialIndex({
1292
+ tiles: tiles,
1293
+ spatialFilter,
1294
+ spatialDataColumn,
1295
+ spatialDataType
1296
+ });
1297
+ }
1298
+ return tileFeaturesGeometries({
1299
+ tiles,
1300
+ tileFormat,
1301
+ spatialFilter,
1302
+ uniqueIdProperty,
1303
+ options
1304
+ });
1305
+ }
1306
+
1307
+ /**
1308
+ * deck.gl's DataFilterExtension supports GPU filtering with 1–4 values. We
1309
+ * allocate filters[0] to generic filters and filters[1] to time filters.
1310
+ *
1311
+ * getFilterValue() _must_ return an array of the same size as the filterSize
1312
+ * used to initialize the DataFilterExtension. We document that users must use
1313
+ * filterSize=4 for compatibility with @link {getDataFilterExtensionProps}.
1314
+ */
1315
+ const DEFAULT_FILTER_SIZE = 4;
1316
+ /**
1317
+ * Creates props for DataFilterExtension, from `@deck.gl/extensions`, given
1318
+ * a set of filters. Requires that DataFilterExtension is initialized with
1319
+ * filterSize=4, where the CARTO filters will occupy the first two slots.
1320
+ *
1321
+ * @example To create a deck.gl layer with GPU data filtering:
1322
+ * ```typescript
1323
+ * import {DataFilterExtension} from '@deck.gl/extensions';
1324
+ * import {VectorTileLayer} from '@deck.gl/layers';
1325
+ * import {getDataFilterExtensionProps} from '@carto/api-client';
1326
+ *
1327
+ * const layer = new VectorTileLayer({
1328
+ * data: data,
1329
+ * extensions: [new DataFilterExtension({filterSize: 4})],
1330
+ * ...getDataFilterExtensionProps(filters),
1331
+ * });
1332
+ * ```
1333
+ */
1334
+ function getDataFilterExtensionProps(filters, filtersLogicalOperator) {
1335
+ const {
1336
+ filtersWithoutTimeType,
1337
+ timeColumn,
1338
+ timeFilter
1339
+ } = getFiltersByType(filters);
1340
+ return {
1341
+ filterRange: getFilterRange(timeFilter, DEFAULT_FILTER_SIZE),
1342
+ updateTriggers: getUpdateTriggers(filtersWithoutTimeType, timeColumn, timeFilter),
1343
+ getFilterValue: getFilterValue(filtersWithoutTimeType, timeColumn, timeFilter, DEFAULT_FILTER_SIZE, filtersLogicalOperator)
1344
+ };
1345
+ }
1346
+ /** @internal */
1347
+ function getFiltersByType(filters) {
1348
+ const filtersWithoutTimeType = {};
1349
+ let timeColumn = null;
1350
+ let timeFilter = null;
1351
+ for (const [column, columnData] of Object.entries(filters)) {
1352
+ for (const [type, typeData] of Object.entries(columnData)) {
1353
+ if (type === exports.FilterType.TIME) {
1354
+ timeColumn = column;
1355
+ timeFilter = typeData;
1356
+ } else {
1357
+ filtersWithoutTimeType[column] = {
1358
+ [type]: typeData
1359
+ };
1360
+ }
1361
+ }
1362
+ }
1363
+ return {
1364
+ filtersWithoutTimeType,
1365
+ timeColumn,
1366
+ timeFilter
1367
+ };
1368
+ }
1369
+ /** @internal */
1370
+ function getFilterRange(timeFilter, filterSize) {
1371
+ const result = Array(filterSize).fill([0, 0]);
1372
+ // According to getFilterValue all filters are resolved as 0 or 1 in the first position of the array
1373
+ // except the time filter value that is resolved with the real value of the feature in the second position of the array
1374
+ result[0] = [1, 1];
1375
+ if (timeFilter) {
1376
+ const offsetBy = timeFilter.params?.offsetBy || 0;
1377
+ result[1] = timeFilter.values[0].map(v => v - offsetBy);
1378
+ }
1379
+ return result;
1380
+ }
1381
+ /** @internal */
1382
+ function getUpdateTriggers(filtersWithoutTimeType, timeColumn, timeFilter) {
1383
+ const result = {
1384
+ ...filtersWithoutTimeType
1385
+ };
1386
+ // We don't want to change the layer UpdateTriggers every time that the time filter changes
1387
+ // because this filter is changed by the time series widget during its animation
1388
+ // so we remove the time filter value from the `updateTriggers`
1389
+ if (timeColumn && timeFilter) {
1390
+ result[timeColumn] = {
1391
+ ...result[timeColumn],
1392
+ offsetBy: timeFilter.params?.offsetBy,
1393
+ [exports.FilterType.TIME]: {} // Allows working with other filters, without an impact on performance.
1394
+ };
1395
+ }
1396
+ return {
1397
+ getFilterValue: JSON.stringify(result)
1398
+ };
1399
+ }
1400
+ /** @internal */
1401
+ function getFilterValue(filtersWithoutTimeType, timeColumn, timeFilter, filterSize, filtersLogicalOperator) {
1402
+ const result = Array(filterSize).fill(0);
1403
+ const featureFilter = _buildFeatureFilter({
1404
+ filters: filtersWithoutTimeType,
1405
+ type: 'number',
1406
+ filtersLogicalOperator
1407
+ });
1408
+ // We evaluate all filters except the time filter using _buildFeatureFilter function.
1409
+ // For the time filter, we return the value of the feature and we will change the getFilterRange result
1410
+ // every time this filter changes
1411
+ return feature => {
1412
+ result[0] = featureFilter(feature);
1413
+ if (timeColumn && timeFilter) {
1414
+ const offsetBy = timeFilter.params?.offsetBy || 0;
1415
+ const f = feature.properties || feature;
1416
+ result[1] = f[timeColumn] - offsetBy;
1417
+ }
1418
+ return result;
1419
+ };
29
1420
  }
30
1421
 
31
- /**
32
- * Defines a comparator used when matching a column's values against given filter values.
33
- *
34
- * Example:
35
- *
36
- * ```javascript
37
- * import { FilterType } from '@carto/api-client';
38
- * const filters = {
39
- * column_name: { [FilterType.IN]: { values: ['a', 'b', 'c'] } }
40
- * };
41
- * ```
42
- *
43
- * @internalRemarks Source: @carto/react-api, @deck.gl/carto
44
- */
45
- exports.FilterType = void 0;
46
- (function (FilterType) {
47
- FilterType["IN"] = "in";
48
- /** [a, b] both are included. */
49
- FilterType["BETWEEN"] = "between";
50
- /** [a, b) a is included, b is not. */
51
- FilterType["CLOSED_OPEN"] = "closed_open";
52
- FilterType["TIME"] = "time";
53
- FilterType["STRING_SEARCH"] = "stringSearch";
54
- })(exports.FilterType || (exports.FilterType = {}));
55
- /** @internalRemarks Source: @carto/constants */
56
- exports.ApiVersion = void 0;
57
- (function (ApiVersion) {
58
- ApiVersion["V1"] = "v1";
59
- ApiVersion["V2"] = "v2";
60
- ApiVersion["V3"] = "v3";
61
- })(exports.ApiVersion || (exports.ApiVersion = {}));
62
- /** @internalRemarks Source: @carto/constants, @deck.gl/carto */
63
- const DEFAULT_API_BASE_URL = 'https://gcp-us-east1.api.carto.com';
64
-
65
1422
  const FILTER_TYPES = new Set(Object.values(exports.FilterType));
66
1423
  const isFilterType = type => FILTER_TYPES.has(type);
67
1424
  /**
@@ -88,7 +1445,7 @@ function getApplicableFilters(owner, filters) {
88
1445
  * Due to each data warehouse having its own behavior with columns,
89
1446
  * we need to normalize them and transform every key to lowercase.
90
1447
  *
91
- * @internalRemarks Source: @carto/react-widgets
1448
+ * @privateRemarks Source: @carto/react-widgets
92
1449
  * @internal
93
1450
  */
94
1451
  function normalizeObjectKeys(el) {
@@ -103,14 +1460,14 @@ function normalizeObjectKeys(el) {
103
1460
  return acc;
104
1461
  }, {});
105
1462
  }
106
- /** @internalRemarks Source: @carto/react-core */
1463
+ /** @privateRemarks Source: @carto/react-core */
107
1464
  function assert(condition, message) {
108
1465
  if (!condition) {
109
1466
  throw new Error(message);
110
1467
  }
111
1468
  }
112
1469
  /**
113
- * @internalRemarks Source: @carto/react-core
1470
+ * @privateRemarks Source: @carto/react-core
114
1471
  * @internal
115
1472
  */
116
1473
  class InvalidColumnError extends Error {
@@ -254,7 +1611,7 @@ function createPolygonSpatialFilter(spatialFilter) {
254
1611
  * Check if a viewport is large enough to represent a global coverage.
255
1612
  * In this case the spatial filter parameter for widget calculation is removed.
256
1613
  *
257
- * @internalRemarks Source: @carto/react-core
1614
+ * @privateRemarks Source: @carto/react-core
258
1615
  */
259
1616
  function _isGlobalViewport(viewport) {
260
1617
  const [minx, miny, maxx, maxy] = viewport;
@@ -267,7 +1624,7 @@ function _isGlobalViewport(viewport) {
267
1624
  *
268
1625
  * It results in a Polygon or MultiPolygon strictly inside the validity range.
269
1626
  *
270
- * @internalRemarks Source: @carto/react-core
1627
+ * @privateRemarks Source: @carto/react-core
271
1628
  */
272
1629
  function _normalizeGeometry(geometry) {
273
1630
  const WORLD = [-180, -90, +180, +90];
@@ -293,17 +1650,17 @@ function _normalizeGeometry(geometry) {
293
1650
  }
294
1651
  return result;
295
1652
  }
296
- /** @internalRemarks Source: @carto/react-core */
1653
+ /** @privateRemarks Source: @carto/react-core */
297
1654
  function _cleanPolygonCoords(cc) {
298
1655
  const coords = cc.filter(c => c.length > 0);
299
1656
  return coords.length > 0 ? coords : null;
300
1657
  }
301
- /** @internalRemarks Source: @carto/react-core */
1658
+ /** @privateRemarks Source: @carto/react-core */
302
1659
  function _cleanMultiPolygonCoords(ccc) {
303
1660
  const coords = ccc.map(_cleanPolygonCoords).filter(cc => cc);
304
1661
  return coords.length > 0 ? coords : null;
305
1662
  }
306
- /** @internalRemarks Source: @carto/react-core */
1663
+ /** @privateRemarks Source: @carto/react-core */
307
1664
  function _clean(geometry) {
308
1665
  if (!geometry) {
309
1666
  return null;
@@ -318,19 +1675,19 @@ function _clean(geometry) {
318
1675
  }
319
1676
  return null;
320
1677
  }
321
- /** @internalRemarks Source: @carto/react-core */
1678
+ /** @privateRemarks Source: @carto/react-core */
322
1679
  function _txContourCoords(cc, distance) {
323
1680
  return cc.map(c => [c[0] + distance, c[1]]);
324
1681
  }
325
- /** @internalRemarks Source: @carto/react-core */
1682
+ /** @privateRemarks Source: @carto/react-core */
326
1683
  function _txPolygonCoords(ccc, distance) {
327
1684
  return ccc.map(cc => _txContourCoords(cc, distance));
328
1685
  }
329
- /** @internalRemarks Source: @carto/react-core */
1686
+ /** @privateRemarks Source: @carto/react-core */
330
1687
  function _txMultiPolygonCoords(cccc, distance) {
331
1688
  return cccc.map(ccc => _txPolygonCoords(ccc, distance));
332
1689
  }
333
- /** @internalRemarks Source: @carto/react-core */
1690
+ /** @privateRemarks Source: @carto/react-core */
334
1691
  function _tx(geometry, distance) {
335
1692
  if (geometry && invariant.getType(geometry) === 'Polygon') {
336
1693
  const coords = _txPolygonCoords(geometry.coordinates, distance);
@@ -349,32 +1706,6 @@ function _isMultiPolygon(geometry) {
349
1706
  return invariant.getType(geometry) === 'MultiPolygon';
350
1707
  }
351
1708
 
352
- /**
353
- * Current version of @carto/api-client.
354
- * @internal
355
- */
356
- /** @internal */
357
- const V3_MINOR_VERSION = '3.4';
358
- /** @internalRemarks Source: @carto/constants, @deck.gl/carto */
359
- const DEFAULT_GEO_COLUMN = 'geom';
360
- /**
361
- * Fastly default limit is 8192; leave some padding.
362
- * @internalRemarks Source: @deck.gl/carto
363
- */
364
- const DEFAULT_MAX_LENGTH_URL = 7000;
365
- /** @internalRemarks Source: @deck.gl/carto */
366
- const DEFAULT_TILE_RESOLUTION = 0.5;
367
- /**
368
- * @internalRemarks Source: @deck.gl/carto
369
- * @internal
370
- */
371
- const DEFAULT_AGGREGATION_RES_LEVEL_H3 = 4;
372
- /**
373
- * @internalRemarks Source: @deck.gl/carto
374
- * @internal
375
- */
376
- const DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN = 6;
377
-
378
1709
  // deck.gl
379
1710
  // SPDX-License-Identifier: MIT
380
1711
  // Copyright (c) vis.gl contributors
@@ -767,12 +2098,106 @@ const boundaryTableSource = function (options) {
767
2098
  }
768
2099
  };
769
2100
 
2101
+ const DEFAULT_TILE_SIZE = 512;
2102
+ const QUADBIN_ZOOM_MAX_OFFSET = 4;
2103
+ function getSpatialFiltersResolution(source, viewState) {
2104
+ const dataResolution = source.dataResolution ?? Number.MAX_VALUE;
2105
+ const aggregationResLevel = source.aggregationResLevel ?? (source.spatialDataType === 'h3' ? DEFAULT_AGGREGATION_RES_LEVEL_H3 : DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN);
2106
+ const aggregationResLevelOffset = Math.max(0, Math.floor(aggregationResLevel));
2107
+ const currentZoomInt = Math.ceil(viewState.zoom);
2108
+ if (source.spatialDataType === 'h3') {
2109
+ const tileSize = DEFAULT_TILE_SIZE;
2110
+ const maxResolutionForZoom = maxH3SpatialFiltersResolutions.find(_ref => {
2111
+ let [zoom] = _ref;
2112
+ return zoom === currentZoomInt;
2113
+ })?.[1] ?? Math.max(0, currentZoomInt - 3);
2114
+ const maxSpatialFiltersResolution = maxResolutionForZoom ? Math.min(dataResolution, maxResolutionForZoom) : dataResolution;
2115
+ const hexagonResolution = _getHexagonResolution(viewState, tileSize) + aggregationResLevelOffset;
2116
+ return Math.min(hexagonResolution, maxSpatialFiltersResolution);
2117
+ }
2118
+ if (source.spatialDataType === 'quadbin') {
2119
+ const maxResolutionForZoom = currentZoomInt + QUADBIN_ZOOM_MAX_OFFSET;
2120
+ const maxSpatialFiltersResolution = Math.min(dataResolution, maxResolutionForZoom);
2121
+ const quadsResolution = Math.floor(viewState.zoom) + aggregationResLevelOffset;
2122
+ return Math.min(quadsResolution, maxSpatialFiltersResolution);
2123
+ }
2124
+ return undefined;
2125
+ }
2126
+ 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]];
2127
+ // stolen from https://github.com/visgl/deck.gl/blob/master/modules/carto/src/layers/h3-tileset-2d.ts
2128
+ // Relative scale factor (0 = no biasing, 2 = a few hexagons cover view)
2129
+ const BIAS = 2;
2130
+ /**
2131
+ * Resolution conversion function. Takes a WebMercatorViewport and returns
2132
+ * a H3 resolution such that the screen space size of the hexagons is
2133
+ * "similar" to the given tileSize on screen. Intended for use with deck.gl.
2134
+ * @internal
2135
+ */
2136
+ function _getHexagonResolution(viewport, tileSize) {
2137
+ // Difference in given tile size compared to deck's internal 512px tile size,
2138
+ // expressed as an offset to the viewport zoom.
2139
+ const zoomOffset = Math.log2(tileSize / DEFAULT_TILE_SIZE);
2140
+ const hexagonScaleFactor = 2 / 3 * (viewport.zoom - zoomOffset);
2141
+ const latitudeScaleFactor = Math.log(1 / Math.cos(Math.PI * viewport.latitude / 180));
2142
+ // Clip and bias
2143
+ return Math.max(0, Math.floor(hexagonScaleFactor + latitudeScaleFactor - BIAS));
2144
+ }
2145
+
2146
+ /**
2147
+ * Source for Widget API requests on a data source defined by a SQL query.
2148
+ *
2149
+ * Abstract class. Use {@link WidgetQuerySource} or {@link WidgetTableSource}.
2150
+ */
2151
+ class WidgetSource {
2152
+ constructor(props) {
2153
+ this.props = void 0;
2154
+ this.props = {
2155
+ ...WidgetSource.defaultProps,
2156
+ clientId: getClient(),
2157
+ // Refresh clientId, default may have changed.
2158
+ ...props
2159
+ };
2160
+ }
2161
+ _getModelSource(filters, filterOwner) {
2162
+ const props = this.props;
2163
+ return {
2164
+ apiVersion: props.apiVersion,
2165
+ apiBaseUrl: props.apiBaseUrl,
2166
+ clientId: props.clientId,
2167
+ accessToken: props.accessToken,
2168
+ connectionName: props.connectionName,
2169
+ filters: getApplicableFilters(filterOwner, filters || props.filters),
2170
+ filtersLogicalOperator: props.filtersLogicalOperator,
2171
+ spatialDataType: props.spatialDataType,
2172
+ spatialDataColumn: props.spatialDataColumn,
2173
+ dataResolution: props.dataResolution
2174
+ };
2175
+ }
2176
+ _getSpatialFiltersResolution(source, spatialFilter, referenceViewState) {
2177
+ // spatialFiltersResolution applies only to spatial index sources.
2178
+ if (!spatialFilter || source.spatialDataType === 'geo') {
2179
+ return;
2180
+ }
2181
+ if (!referenceViewState) {
2182
+ throw new Error('Missing required option, "spatialIndexReferenceViewState".');
2183
+ }
2184
+ return getSpatialFiltersResolution(source, referenceViewState);
2185
+ }
2186
+ }
2187
+ WidgetSource.defaultProps = {
2188
+ apiVersion: exports.ApiVersion.V3,
2189
+ apiBaseUrl: DEFAULT_API_BASE_URL,
2190
+ clientId: getClient(),
2191
+ filters: {},
2192
+ filtersLogicalOperator: 'and'
2193
+ };
2194
+
770
2195
  /**
771
2196
  * Return more descriptive error from API
772
- * @internalRemarks Source: @carto/react-api
2197
+ * @privateRemarks Source: @carto/react-api
773
2198
  */
774
2199
 
775
- /** @internalRemarks Source: @carto/react-api */
2200
+ /** @privateRemarks Source: @carto/react-api */
776
2201
 
777
2202
  function _catch(body, recover) {
778
2203
  try {
@@ -812,13 +2237,14 @@ const makeCall = function (_ref2) {
812
2237
  Authorization: `Bearer ${accessToken}`,
813
2238
  ...(isPost && {
814
2239
  'Content-Type': 'application/json'
815
- })
2240
+ }),
2241
+ ...opts.headers
816
2242
  },
817
2243
  ...(isPost && {
818
2244
  method: opts?.method,
819
2245
  body: opts?.body
820
2246
  }),
821
- signal: opts?.abortController?.signal,
2247
+ signal: opts?.signal,
822
2248
  ...opts?.otherOptions
823
2249
  })).then(function (_fetch) {
824
2250
  response = _fetch;
@@ -852,12 +2278,11 @@ function dealWithApiError(_ref) {
852
2278
  case 403:
853
2279
  throw new Error('Forbidden access to the requested data');
854
2280
  default:
855
- const msg = data && data.error && typeof data.error === 'string' ? data.error : JSON.stringify(data?.hint || data.error?.[0]);
856
- throw new Error(msg);
2281
+ throw new Error(data && data.error && typeof data.error === 'string' ? data.error : JSON.stringify(data?.hint || data.error?.[0]));
857
2282
  }
858
2283
  }
859
2284
 
860
- /** @internalRemarks Source: @carto/react-api */
2285
+ /** @privateRemarks Source: @carto/react-api */
861
2286
  const AVAILABLE_MODELS = ['category', 'histogram', 'formula', 'pick', 'timeseries', 'range', 'scatterplot', 'table'];
862
2287
  const {
863
2288
  V3
@@ -865,7 +2290,7 @@ const {
865
2290
  const REQUEST_GET_MAX_URL_LENGTH = 2048;
866
2291
  /**
867
2292
  * Execute a SQL model request.
868
- * @internalRemarks Source: @carto/react-api
2293
+ * @privateRemarks Source: @carto/react-api
869
2294
  */
870
2295
  function executeModel(props) {
871
2296
  assert(props.source, 'executeModel: missing source');
@@ -961,105 +2386,22 @@ function objectToURLSearchParams(object) {
961
2386
  return params;
962
2387
  }
963
2388
 
964
- const DEFAULT_TILE_SIZE = 512;
965
- const QUADBIN_ZOOM_MAX_OFFSET = 4;
966
- function getSpatialFiltersResolution(source, viewState) {
967
- const dataResolution = source.dataResolution ?? Number.MAX_VALUE;
968
- const aggregationResLevel = source.aggregationResLevel ?? (source.spatialDataType === 'h3' ? DEFAULT_AGGREGATION_RES_LEVEL_H3 : DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN);
969
- const aggregationResLevelOffset = Math.max(0, Math.floor(aggregationResLevel));
970
- const currentZoomInt = Math.ceil(viewState.zoom);
971
- if (source.spatialDataType === 'h3') {
972
- const tileSize = DEFAULT_TILE_SIZE;
973
- const maxResolutionForZoom = maxH3SpatialFiltersResolutions.find(_ref => {
974
- let [zoom] = _ref;
975
- return zoom === currentZoomInt;
976
- })?.[1] ?? Math.max(0, currentZoomInt - 3);
977
- const maxSpatialFiltersResolution = maxResolutionForZoom ? Math.min(dataResolution, maxResolutionForZoom) : dataResolution;
978
- const hexagonResolution = _getHexagonResolution(viewState, tileSize) + aggregationResLevelOffset;
979
- return Math.min(hexagonResolution, maxSpatialFiltersResolution);
980
- }
981
- if (source.spatialDataType === 'quadbin') {
982
- const maxResolutionForZoom = currentZoomInt + QUADBIN_ZOOM_MAX_OFFSET;
983
- const maxSpatialFiltersResolution = Math.min(dataResolution, maxResolutionForZoom);
984
- const quadsResolution = Math.floor(viewState.zoom) + aggregationResLevelOffset;
985
- return Math.min(quadsResolution, maxSpatialFiltersResolution);
986
- }
987
- return undefined;
988
- }
989
- 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]];
990
- // stolen from https://github.com/visgl/deck.gl/blob/master/modules/carto/src/layers/h3-tileset-2d.ts
991
- // Relative scale factor (0 = no biasing, 2 = a few hexagons cover view)
992
- const BIAS = 2;
993
- /**
994
- * Resolution conversion function. Takes a WebMercatorViewport and returns
995
- * a H3 resolution such that the screen space size of the hexagons is
996
- * "similar" to the given tileSize on screen. Intended for use with deck.gl.
997
- * @internal
998
- */
999
- function _getHexagonResolution(viewport, tileSize) {
1000
- // Difference in given tile size compared to deck's internal 512px tile size,
1001
- // expressed as an offset to the viewport zoom.
1002
- const zoomOffset = Math.log2(tileSize / DEFAULT_TILE_SIZE);
1003
- const hexagonScaleFactor = 2 / 3 * (viewport.zoom - zoomOffset);
1004
- const latitudeScaleFactor = Math.log(1 / Math.cos(Math.PI * viewport.latitude / 180));
1005
- // Clip and bias
1006
- return Math.max(0, Math.floor(hexagonScaleFactor + latitudeScaleFactor - BIAS));
1007
- }
1008
-
1009
2389
  /**
1010
- * Source for Widget API requests on a data source defined by a SQL query.
2390
+ * Source for Widget API requests.
1011
2391
  *
1012
2392
  * Abstract class. Use {@link WidgetQuerySource} or {@link WidgetTableSource}.
1013
2393
  */
1014
- class WidgetBaseSource {
1015
- constructor(props) {
1016
- this.props = void 0;
1017
- this.props = {
1018
- ...WidgetBaseSource.defaultProps,
1019
- ...props
1020
- };
1021
- }
1022
- _getModelSource(owner) {
1023
- const props = this.props;
1024
- return {
1025
- apiVersion: props.apiVersion,
1026
- apiBaseUrl: props.apiBaseUrl,
1027
- clientId: props.clientId,
1028
- accessToken: props.accessToken,
1029
- connectionName: props.connectionName,
1030
- filters: getApplicableFilters(owner, props.filters),
1031
- filtersLogicalOperator: props.filtersLogicalOperator,
1032
- spatialDataType: props.spatialDataType,
1033
- spatialDataColumn: props.spatialDataColumn,
1034
- dataResolution: props.dataResolution
1035
- };
1036
- }
1037
- _getSpatialFiltersResolution(source, spatialFilter, referenceViewState) {
1038
- // spatialFiltersResolution applies only to spatial index sources.
1039
- if (!spatialFilter || source.spatialDataType === 'geo') {
1040
- return;
1041
- }
1042
- if (!referenceViewState) {
1043
- throw new Error('Missing required option, "spatialIndexReferenceViewState".');
1044
- }
1045
- return getSpatialFiltersResolution(source, referenceViewState);
1046
- }
1047
- /****************************************************************************
1048
- * CATEGORIES
1049
- */
1050
- /**
1051
- * Returns a list of labeled datapoints for categorical data. Suitable for
1052
- * charts including grouped bar charts, pie charts, and tree charts.
1053
- */
2394
+ class WidgetRemoteSource extends WidgetSource {
1054
2395
  getCategories(options) {
1055
2396
  try {
1056
2397
  const _this = this;
1057
2398
  const {
2399
+ signal,
2400
+ filters = _this.props.filters,
1058
2401
  filterOwner,
1059
2402
  spatialFilter,
1060
2403
  spatialFiltersMode,
1061
2404
  spatialIndexReferenceViewState,
1062
- abortController,
1063
2405
  ...params
1064
2406
  } = options;
1065
2407
  const {
@@ -1067,7 +2409,7 @@ class WidgetBaseSource {
1067
2409
  operation,
1068
2410
  operationColumn
1069
2411
  } = params;
1070
- const source = _this.getModelSource(filterOwner);
2412
+ const source = _this.getModelSource(filters, filterOwner);
1071
2413
  const spatialFiltersResolution = _this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
1072
2414
  return Promise.resolve(executeModel({
1073
2415
  model: 'category',
@@ -1083,33 +2425,25 @@ class WidgetBaseSource {
1083
2425
  operationColumn: operationColumn || column
1084
2426
  },
1085
2427
  opts: {
1086
- abortController
2428
+ signal,
2429
+ headers: _this.props.headers
1087
2430
  }
1088
2431
  }).then(res => normalizeObjectKeys(res.rows)));
1089
2432
  } catch (e) {
1090
2433
  return Promise.reject(e);
1091
2434
  }
1092
2435
  }
1093
- /****************************************************************************
1094
- * FEATURES
1095
- */
1096
- /**
1097
- * Given a list of feature IDs (as found in `_carto_feature_id`) returns all
1098
- * matching features. In datasets containing features with duplicate geometries,
1099
- * feature IDs may be duplicated (IDs are a hash of geometry) and so more
1100
- * results may be returned than IDs in the request.
1101
- * @internal
1102
- * @experimental
1103
- */
1104
2436
  getFeatures(options) {
1105
2437
  try {
1106
2438
  const _this2 = this;
1107
2439
  const {
2440
+ abortController,
2441
+ signal = abortController?.signal,
2442
+ filters = _this2.props.filters,
1108
2443
  filterOwner,
1109
2444
  spatialFilter,
1110
2445
  spatialFiltersMode,
1111
2446
  spatialIndexReferenceViewState,
1112
- abortController,
1113
2447
  ...params
1114
2448
  } = options;
1115
2449
  const {
@@ -1120,7 +2454,7 @@ class WidgetBaseSource {
1120
2454
  limit,
1121
2455
  tileResolution
1122
2456
  } = params;
1123
- const source = _this2.getModelSource(filterOwner);
2457
+ const source = _this2.getModelSource(filters, filterOwner);
1124
2458
  const spatialFiltersResolution = _this2._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
1125
2459
  return Promise.resolve(executeModel({
1126
2460
  model: 'pick',
@@ -1139,7 +2473,8 @@ class WidgetBaseSource {
1139
2473
  tileResolution: tileResolution || DEFAULT_TILE_RESOLUTION
1140
2474
  },
1141
2475
  opts: {
1142
- abortController
2476
+ signal,
2477
+ headers: _this2.props.headers
1143
2478
  }
1144
2479
  // Avoid `normalizeObjectKeys()`, which changes column names.
1145
2480
  }).then(_ref => {
@@ -1154,22 +2489,17 @@ class WidgetBaseSource {
1154
2489
  return Promise.reject(e);
1155
2490
  }
1156
2491
  }
1157
- /****************************************************************************
1158
- * FORMULA
1159
- */
1160
- /**
1161
- * Returns a scalar numerical statistic over all matching data. Suitable
1162
- * for 'headline' or 'scorecard' figures such as counts and sums.
1163
- */
1164
2492
  getFormula(options) {
1165
2493
  try {
1166
2494
  const _this3 = this;
1167
2495
  const {
2496
+ abortController,
2497
+ signal = abortController?.signal,
2498
+ filters = _this3.props.filters,
1168
2499
  filterOwner,
1169
2500
  spatialFilter,
1170
2501
  spatialFiltersMode,
1171
2502
  spatialIndexReferenceViewState,
1172
- abortController,
1173
2503
  operationExp,
1174
2504
  ...params
1175
2505
  } = options;
@@ -1177,7 +2507,7 @@ class WidgetBaseSource {
1177
2507
  column,
1178
2508
  operation
1179
2509
  } = params;
1180
- const source = _this3.getModelSource(filterOwner);
2510
+ const source = _this3.getModelSource(filters, filterOwner);
1181
2511
  const spatialFiltersResolution = _this3._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
1182
2512
  return Promise.resolve(executeModel({
1183
2513
  model: 'formula',
@@ -1189,33 +2519,29 @@ class WidgetBaseSource {
1189
2519
  },
1190
2520
  params: {
1191
2521
  column: column ?? '*',
1192
- operation,
2522
+ operation: operation ?? 'count',
1193
2523
  operationExp
1194
2524
  },
1195
2525
  opts: {
1196
- abortController
2526
+ signal,
2527
+ headers: _this3.props.headers
1197
2528
  }
1198
2529
  }).then(res => normalizeObjectKeys(res.rows[0])));
1199
2530
  } catch (e) {
1200
2531
  return Promise.reject(e);
1201
2532
  }
1202
2533
  }
1203
- /****************************************************************************
1204
- * HISTOGRAM
1205
- */
1206
- /**
1207
- * Returns a list of labeled datapoints for 'bins' of data defined as ticks
1208
- * over a numerical range. Suitable for histogram charts.
1209
- */
1210
2534
  getHistogram(options) {
1211
2535
  try {
1212
2536
  const _this4 = this;
1213
2537
  const {
2538
+ abortController,
2539
+ signal = abortController?.signal,
2540
+ filters = _this4.props.filters,
1214
2541
  filterOwner,
1215
2542
  spatialFilter,
1216
2543
  spatialFiltersMode,
1217
2544
  spatialIndexReferenceViewState,
1218
- abortController,
1219
2545
  ...params
1220
2546
  } = options;
1221
2547
  const {
@@ -1223,7 +2549,7 @@ class WidgetBaseSource {
1223
2549
  operation,
1224
2550
  ticks
1225
2551
  } = params;
1226
- const source = _this4.getModelSource(filterOwner);
2552
+ const source = _this4.getModelSource(filters, filterOwner);
1227
2553
  const spatialFiltersResolution = _this4._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
1228
2554
  return Promise.resolve(executeModel({
1229
2555
  model: 'histogram',
@@ -1239,7 +2565,8 @@ class WidgetBaseSource {
1239
2565
  ticks
1240
2566
  },
1241
2567
  opts: {
1242
- abortController
2568
+ signal,
2569
+ headers: _this4.props.headers
1243
2570
  }
1244
2571
  }).then(res => normalizeObjectKeys(res.rows))).then(function (data) {
1245
2572
  if (data.length) {
@@ -1261,29 +2588,23 @@ class WidgetBaseSource {
1261
2588
  return Promise.reject(e);
1262
2589
  }
1263
2590
  }
1264
- /****************************************************************************
1265
- * RANGE
1266
- */
1267
- /**
1268
- * Returns a range (min and max) for a numerical column of matching rows.
1269
- * Suitable for displaying certain 'headline' or 'scorecard' statistics,
1270
- * or rendering a range slider UI for filtering.
1271
- */
1272
2591
  getRange(options) {
1273
2592
  try {
1274
2593
  const _this5 = this;
1275
2594
  const {
2595
+ abortController,
2596
+ signal = abortController?.signal,
2597
+ filters = _this5.props.filters,
1276
2598
  filterOwner,
1277
2599
  spatialFilter,
1278
2600
  spatialFiltersMode,
1279
2601
  spatialIndexReferenceViewState,
1280
- abortController,
1281
2602
  ...params
1282
2603
  } = options;
1283
2604
  const {
1284
2605
  column
1285
2606
  } = params;
1286
- const source = _this5.getModelSource(filterOwner);
2607
+ const source = _this5.getModelSource(filters, filterOwner);
1287
2608
  const spatialFiltersResolution = _this5._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
1288
2609
  return Promise.resolve(executeModel({
1289
2610
  model: 'range',
@@ -1297,29 +2618,25 @@ class WidgetBaseSource {
1297
2618
  column
1298
2619
  },
1299
2620
  opts: {
1300
- abortController
2621
+ signal,
2622
+ headers: _this5.props.headers
1301
2623
  }
1302
2624
  }).then(res => normalizeObjectKeys(res.rows[0])));
1303
2625
  } catch (e) {
1304
2626
  return Promise.reject(e);
1305
2627
  }
1306
2628
  }
1307
- /****************************************************************************
1308
- * SCATTER
1309
- */
1310
- /**
1311
- * Returns a list of bivariate datapoints defined as numerical 'x' and 'y'
1312
- * values. Suitable for rendering scatter plots.
1313
- */
1314
2629
  getScatter(options) {
1315
2630
  try {
1316
2631
  const _this6 = this;
1317
2632
  const {
2633
+ abortController,
2634
+ signal = abortController?.signal,
2635
+ filters = _this6.props.filters,
1318
2636
  filterOwner,
1319
2637
  spatialFilter,
1320
2638
  spatialFiltersMode,
1321
2639
  spatialIndexReferenceViewState,
1322
- abortController,
1323
2640
  ...params
1324
2641
  } = options;
1325
2642
  const {
@@ -1328,7 +2645,7 @@ class WidgetBaseSource {
1328
2645
  yAxisColumn,
1329
2646
  yAxisJoinOperation
1330
2647
  } = params;
1331
- const source = _this6.getModelSource(filterOwner);
2648
+ const source = _this6.getModelSource(filters, filterOwner);
1332
2649
  const spatialFiltersResolution = _this6._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
1333
2650
  // Make sure this is sync with the same constant in cloud-native/maps-api
1334
2651
  const HARD_LIMIT = 500;
@@ -1348,7 +2665,8 @@ class WidgetBaseSource {
1348
2665
  limit: HARD_LIMIT
1349
2666
  },
1350
2667
  opts: {
1351
- abortController
2668
+ signal,
2669
+ headers: _this6.props.headers
1352
2670
  }
1353
2671
  }).then(res => normalizeObjectKeys(res.rows)).then(res => res.map(_ref3 => {
1354
2672
  let {
@@ -1361,22 +2679,17 @@ class WidgetBaseSource {
1361
2679
  return Promise.reject(e);
1362
2680
  }
1363
2681
  }
1364
- /****************************************************************************
1365
- * TABLE
1366
- */
1367
- /**
1368
- * Returns a list of arbitrary data rows, with support for pagination and
1369
- * sorting. Suitable for displaying tables and lists.
1370
- */
1371
2682
  getTable(options) {
1372
2683
  try {
1373
2684
  const _this7 = this;
1374
2685
  const {
2686
+ abortController,
2687
+ signal = abortController?.signal,
2688
+ filters = _this7.props.filters,
1375
2689
  filterOwner,
1376
2690
  spatialFilter,
1377
2691
  spatialFiltersMode,
1378
2692
  spatialIndexReferenceViewState,
1379
- abortController,
1380
2693
  ...params
1381
2694
  } = options;
1382
2695
  const {
@@ -1386,7 +2699,7 @@ class WidgetBaseSource {
1386
2699
  offset = 0,
1387
2700
  limit = 10
1388
2701
  } = params;
1389
- const source = _this7.getModelSource(filterOwner);
2702
+ const source = _this7.getModelSource(filters, filterOwner);
1390
2703
  const spatialFiltersResolution = _this7._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
1391
2704
  return Promise.resolve(executeModel({
1392
2705
  model: 'table',
@@ -1404,7 +2717,8 @@ class WidgetBaseSource {
1404
2717
  offset
1405
2718
  },
1406
2719
  opts: {
1407
- abortController
2720
+ signal,
2721
+ headers: _this7.props.headers
1408
2722
  }
1409
2723
  }).then(res => ({
1410
2724
  // Avoid `normalizeObjectKeys()`, which changes column names.
@@ -1415,19 +2729,14 @@ class WidgetBaseSource {
1415
2729
  return Promise.reject(e);
1416
2730
  }
1417
2731
  }
1418
- /****************************************************************************
1419
- * TIME SERIES
1420
- */
1421
- /**
1422
- * Returns a series of labeled numerical values, grouped into equally-sized
1423
- * time intervals. Suitable for rendering time series charts.
1424
- */
1425
2732
  getTimeSeries(options) {
1426
2733
  try {
1427
2734
  const _this8 = this;
1428
2735
  const {
1429
- filterOwner,
1430
2736
  abortController,
2737
+ signal = abortController?.signal,
2738
+ filters = _this8.props.filters,
2739
+ filterOwner,
1431
2740
  spatialFilter,
1432
2741
  spatialFiltersMode,
1433
2742
  spatialIndexReferenceViewState,
@@ -1444,7 +2753,7 @@ class WidgetBaseSource {
1444
2753
  splitByCategoryLimit,
1445
2754
  splitByCategoryValues
1446
2755
  } = params;
1447
- const source = _this8.getModelSource(filterOwner);
2756
+ const source = _this8.getModelSource(filters, filterOwner);
1448
2757
  const spatialFiltersResolution = _this8._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
1449
2758
  return Promise.resolve(executeModel({
1450
2759
  model: 'timeseries',
@@ -1466,7 +2775,8 @@ class WidgetBaseSource {
1466
2775
  splitByCategoryValues
1467
2776
  },
1468
2777
  opts: {
1469
- abortController
2778
+ signal,
2779
+ headers: _this8.props.headers
1470
2780
  }
1471
2781
  }).then(res => ({
1472
2782
  rows: normalizeObjectKeys(res.rows),
@@ -1477,13 +2787,6 @@ class WidgetBaseSource {
1477
2787
  }
1478
2788
  }
1479
2789
  }
1480
- WidgetBaseSource.defaultProps = {
1481
- apiVersion: exports.ApiVersion.V3,
1482
- apiBaseUrl: DEFAULT_API_BASE_URL,
1483
- clientId: getClient(),
1484
- filters: {},
1485
- filtersLogicalOperator: 'and'
1486
- };
1487
2790
 
1488
2791
  /**
1489
2792
  * Source for Widget API requests on a data source defined by a SQL query.
@@ -1507,10 +2810,10 @@ WidgetBaseSource.defaultProps = {
1507
2810
  * const { widgetSource } = await data;
1508
2811
  * ```
1509
2812
  */
1510
- class WidgetQuerySource extends WidgetBaseSource {
1511
- getModelSource(owner) {
2813
+ class WidgetQuerySource extends WidgetRemoteSource {
2814
+ getModelSource(filters, filterOwner) {
1512
2815
  return {
1513
- ...super._getModelSource(owner),
2816
+ ...super._getModelSource(filters, filterOwner),
1514
2817
  type: 'query',
1515
2818
  data: this.props.sqlQuery,
1516
2819
  queryParameters: this.props.queryParameters
@@ -1540,20 +2843,787 @@ class WidgetQuerySource extends WidgetBaseSource {
1540
2843
  * const { widgetSource } = await data;
1541
2844
  * ```
1542
2845
  */
1543
- class WidgetTableSource extends WidgetBaseSource {
1544
- getModelSource(owner) {
2846
+ class WidgetTableSource extends WidgetRemoteSource {
2847
+ getModelSource(filters, filterOwner) {
1545
2848
  return {
1546
- ...super._getModelSource(owner),
2849
+ ...super._getModelSource(filters, filterOwner),
1547
2850
  type: 'table',
1548
2851
  data: this.props.tableName
1549
2852
  };
1550
2853
  }
1551
2854
  }
1552
2855
 
2856
+ /** @privateRemarks Source: @carto/react-core */
2857
+ const aggregationFunctions = {
2858
+ count: values => values.length,
2859
+ min: function () {
2860
+ return applyAggregationFunction(min, ...[].slice.call(arguments));
2861
+ },
2862
+ max: function () {
2863
+ return applyAggregationFunction(max, ...[].slice.call(arguments));
2864
+ },
2865
+ sum: function () {
2866
+ return applyAggregationFunction(sum, ...[].slice.call(arguments));
2867
+ },
2868
+ avg: function () {
2869
+ return applyAggregationFunction(avg, ...[].slice.call(arguments));
2870
+ }
2871
+ };
2872
+ /** @privateRemarks Source: @carto/react-core */
2873
+ function aggregate(feature, keys, operation) {
2874
+ if (!keys?.length) {
2875
+ throw new Error('Cannot aggregate a feature without having keys');
2876
+ } else if (keys.length === 1) {
2877
+ const value = feature[keys[0]];
2878
+ return isPotentiallyValidNumber(value) ? Number(value) : value;
2879
+ }
2880
+ const aggregationFn = aggregationFunctions[operation];
2881
+ if (!aggregationFn) {
2882
+ throw new Error(`${operation} isn't a valid aggregation function`);
2883
+ }
2884
+ return aggregationFn(keys.map(column => {
2885
+ const value = feature[column];
2886
+ return isPotentiallyValidNumber(value) ? Number(value) : value;
2887
+ }));
2888
+ }
2889
+ /*
2890
+ * Forced casting to Number (just of non empty strings) allows to work-around
2891
+ * some specific situations, where a big numeric field is transformed into a string when generating the tileset(eg.PG)
2892
+ */
2893
+ function isPotentiallyValidNumber(value) {
2894
+ return typeof value === 'string' && value.trim().length > 0;
2895
+ }
2896
+ const applyAggregationFunction = (aggFn, values, keys, operation) => {
2897
+ const normalizedKeys = normalizeKeys(keys);
2898
+ const elements = (normalizedKeys?.length || 0) <= 1 ? filterFalsyElements(values, normalizedKeys || []) : values;
2899
+ return aggFn(elements, keys, operation);
2900
+ };
2901
+ function filterFalsyElements(values, keys) {
2902
+ const filterFn = value => value !== null && value !== undefined;
2903
+ if (!keys?.length) {
2904
+ return values.filter(filterFn);
2905
+ }
2906
+ return values.filter(v => filterFn(v[keys[0]]));
2907
+ }
2908
+ // Aggregation functions
2909
+ function avg(values, keys, joinOperation) {
2910
+ return sum(values, keys, joinOperation) / (values.length || 1);
2911
+ }
2912
+ function sum(values, keys, joinOperation) {
2913
+ const normalizedKeys = normalizeKeys(keys);
2914
+ if (normalizedKeys) {
2915
+ return values.reduce((a, b) => a + aggregate(b, normalizedKeys, joinOperation), 0);
2916
+ }
2917
+ return values.reduce((a, b) => a + b, 0);
2918
+ }
2919
+ function min(values, keys, joinOperation) {
2920
+ const normalizedKeys = normalizeKeys(keys);
2921
+ if (normalizedKeys) {
2922
+ return values.reduce((a, b) => Math.min(a, aggregate(b, normalizedKeys, joinOperation)), Infinity);
2923
+ }
2924
+ return Math.min(...values);
2925
+ }
2926
+ function max(values, keys, joinOperation) {
2927
+ const normalizedKeys = normalizeKeys(keys);
2928
+ if (normalizedKeys) {
2929
+ return values.reduce((a, b) => Math.max(a, aggregate(b, normalizedKeys, joinOperation)), -Infinity);
2930
+ }
2931
+ return Math.max(...values);
2932
+ }
2933
+ // Aux
2934
+ // Keys can come as a string (one column) or a strings array (multiple column)
2935
+ // Use always an array to make the code easier
2936
+ function normalizeKeys(keys) {
2937
+ return Array.isArray(keys) ? keys : typeof keys === 'string' ? [keys] : undefined;
2938
+ }
2939
+
2940
+ /***
2941
+ Copyright 2013 Teun Duynstee
2942
+
2943
+ Licensed under the Apache License, Version 2.0 (the "License");
2944
+ you may not use this file except in compliance with the License.
2945
+ You may obtain a copy of the License at
2946
+
2947
+ http://www.apache.org/licenses/LICENSE-2.0
2948
+
2949
+ Unless required by applicable law or agreed to in writing, software
2950
+ distributed under the License is distributed on an "AS IS" BASIS,
2951
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2952
+ See the License for the specific language governing permissions and
2953
+ limitations under the License.
2954
+ */
2955
+ var thenBy_module = function () {
2956
+ function identity(v) {
2957
+ return v;
2958
+ }
2959
+ function ignoreCase(v) {
2960
+ return typeof v === "string" ? v.toLowerCase() : v;
2961
+ }
2962
+ function makeCompareFunction(f, opt) {
2963
+ opt = typeof opt === "object" ? opt : {
2964
+ direction: opt
2965
+ };
2966
+ if (typeof f != "function") {
2967
+ var prop = f;
2968
+ // make unary function
2969
+ f = function (v1) {
2970
+ return !!v1[prop] ? v1[prop] : "";
2971
+ };
2972
+ }
2973
+ if (f.length === 1) {
2974
+ // f is a unary function mapping a single item to its sort score
2975
+ var uf = f;
2976
+ var preprocess = opt.ignoreCase ? ignoreCase : identity;
2977
+ var cmp = opt.cmp || function (v1, v2) {
2978
+ return v1 < v2 ? -1 : v1 > v2 ? 1 : 0;
2979
+ };
2980
+ f = function (v1, v2) {
2981
+ return cmp(preprocess(uf(v1)), preprocess(uf(v2)));
2982
+ };
2983
+ }
2984
+ const descTokens = {
2985
+ "-1": '',
2986
+ desc: ''
2987
+ };
2988
+ if (opt.direction in descTokens) return function (v1, v2) {
2989
+ return -f(v1, v2);
2990
+ };
2991
+ return f;
2992
+ }
2993
+
2994
+ /* adds a secondary compare function to the target function (`this` context)
2995
+ which is applied in case the first one returns 0 (equal)
2996
+ returns a new compare function, which has a `thenBy` method as well */
2997
+ function tb(func, opt) {
2998
+ /* should get value false for the first call. This can be done by calling the
2999
+ exported function, or the firstBy property on it (for es6 module compatibility)
3000
+ */
3001
+ var x = typeof this == "function" && !this.firstBy ? this : false;
3002
+ var y = makeCompareFunction(func, opt);
3003
+ var f = x ? function (a, b) {
3004
+ return x(a, b) || y(a, b);
3005
+ } : y;
3006
+ f.thenBy = tb;
3007
+ return f;
3008
+ }
3009
+ tb.firstBy = tb;
3010
+ return tb;
3011
+ }();
3012
+
3013
+ /**
3014
+ * Apply sort structure to a collection of features
3015
+ * @param features
3016
+ * @param [sortOptions]
3017
+ * @param [sortOptions.sortBy] - One or more columns to sort by
3018
+ * @param [sortOptions.sortByDirection] - Direction by the columns will be sorted
3019
+ * @param [sortOptions.sortByColumnType] - Column type
3020
+ * @internal
3021
+ * @privateRemarks Source: @carto/react-core
3022
+ */
3023
+ function applySorting(features, _temp) {
3024
+ let {
3025
+ sortBy,
3026
+ sortByDirection = 'asc',
3027
+ sortByColumnType = 'string'
3028
+ } = _temp === void 0 ? {} : _temp;
3029
+ // If sortBy is undefined, pass all features
3030
+ if (sortBy === undefined) {
3031
+ return features;
3032
+ }
3033
+ // sortOptions exists, but are bad formatted
3034
+ const isValidSortBy = Array.isArray(sortBy) && sortBy.length ||
3035
+ // sortBy can be an array of columns
3036
+ typeof sortBy === 'string'; // or just one column
3037
+ if (!isValidSortBy) {
3038
+ throw new Error('Sorting options are bad formatted');
3039
+ }
3040
+ const sortFn = createSortFn({
3041
+ sortBy,
3042
+ sortByDirection,
3043
+ sortByColumnType: sortByColumnType || 'string'
3044
+ });
3045
+ return features.sort(sortFn);
3046
+ }
3047
+ // Aux
3048
+ function createSortFn(_ref) {
3049
+ let {
3050
+ sortBy,
3051
+ sortByDirection,
3052
+ sortByColumnType
3053
+ } = _ref;
3054
+ const [firstSortOption, ...othersSortOptions] = normalizeSortByOptions({
3055
+ sortBy,
3056
+ sortByDirection,
3057
+ sortByColumnType
3058
+ });
3059
+ let sortFn = thenBy_module.firstBy(...firstSortOption);
3060
+ for (const sortOptions of othersSortOptions) {
3061
+ sortFn = sortFn.thenBy(...sortOptions);
3062
+ }
3063
+ return sortFn;
3064
+ }
3065
+ function normalizeSortByOptions(_ref2) {
3066
+ let {
3067
+ sortBy,
3068
+ sortByDirection,
3069
+ sortByColumnType
3070
+ } = _ref2;
3071
+ const numberFormat = sortByColumnType === 'number' && {
3072
+ cmp: (a, b) => a - b
3073
+ };
3074
+ if (!Array.isArray(sortBy)) {
3075
+ sortBy = [sortBy];
3076
+ }
3077
+ return sortBy.map(sortByEl => {
3078
+ // sortByEl is 'column'
3079
+ if (typeof sortByEl === 'string') {
3080
+ return [sortByEl, {
3081
+ direction: sortByDirection,
3082
+ ...numberFormat
3083
+ }];
3084
+ }
3085
+ if (Array.isArray(sortByEl)) {
3086
+ // sortBy is ['column']
3087
+ if (sortByEl[1] === undefined) {
3088
+ return [sortByEl, {
3089
+ direction: sortByDirection,
3090
+ ...numberFormat
3091
+ }];
3092
+ }
3093
+ // sortBy is ['column', { ... }]
3094
+ if (typeof sortByEl[1] === 'object') {
3095
+ const othersSortOptions = numberFormat ? {
3096
+ ...numberFormat,
3097
+ ...sortByEl[1]
3098
+ } : sortByEl[1];
3099
+ return [sortByEl[0], {
3100
+ direction: sortByDirection,
3101
+ ...othersSortOptions
3102
+ }];
3103
+ }
3104
+ }
3105
+ return sortByEl;
3106
+ });
3107
+ }
3108
+
3109
+ /** @privateRemarks Source: @carto/react-core */
3110
+ function groupValuesByColumn(_ref) {
3111
+ let {
3112
+ data,
3113
+ valuesColumns,
3114
+ joinOperation,
3115
+ keysColumn,
3116
+ operation
3117
+ } = _ref;
3118
+ if (Array.isArray(data) && data.length === 0) {
3119
+ return null;
3120
+ }
3121
+ const groups = data.reduce((accumulator, item) => {
3122
+ const group = item[keysColumn];
3123
+ const values = accumulator.get(group) || [];
3124
+ accumulator.set(group, values);
3125
+ const aggregatedValue = aggregate(item, valuesColumns, joinOperation);
3126
+ const isValid = (operation === 'count' ? true : aggregatedValue !== null) && aggregatedValue !== undefined;
3127
+ if (isValid) {
3128
+ values.push(aggregatedValue);
3129
+ accumulator.set(group, values);
3130
+ }
3131
+ return accumulator;
3132
+ }, new Map()); // We use a map to be able to maintain the type in the key value
3133
+ const targetOperation = aggregationFunctions[operation];
3134
+ if (targetOperation) {
3135
+ return Array.from(groups).map(_ref2 => {
3136
+ let [name, value] = _ref2;
3137
+ return {
3138
+ name,
3139
+ value: targetOperation(value)
3140
+ };
3141
+ });
3142
+ }
3143
+ return [];
3144
+ }
3145
+
3146
+ /**
3147
+ * Returns midnight (local time) on the Monday preceeding a given date, in
3148
+ * milliseconds since the UNIX epoch.
3149
+ */
3150
+ /**
3151
+ * Returns midnight (UTC) on the Monday preceeding a given date, in
3152
+ * milliseconds since the UNIX epoch.
3153
+ */
3154
+ function getUTCMonday(date) {
3155
+ const dateCp = new Date(date);
3156
+ const day = dateCp.getUTCDay();
3157
+ const diff = dateCp.getUTCDate() - day + (day ? 1 : -6); // adjust when day is sunday
3158
+ dateCp.setUTCDate(diff);
3159
+ return Date.UTC(dateCp.getUTCFullYear(), dateCp.getUTCMonth(), dateCp.getUTCDate());
3160
+ }
3161
+
3162
+ const GROUP_KEY_FN_MAPPING = {
3163
+ year: date => Date.UTC(date.getUTCFullYear()),
3164
+ month: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth()),
3165
+ week: date => getUTCMonday(date),
3166
+ day: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()),
3167
+ hour: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours()),
3168
+ minute: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes()),
3169
+ second: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds())
3170
+ };
3171
+ /** @privateRemarks Source: @carto/react-core */
3172
+ function groupValuesByDateColumn(_ref) {
3173
+ let {
3174
+ data,
3175
+ valuesColumns,
3176
+ joinOperation,
3177
+ keysColumn,
3178
+ groupType,
3179
+ operation
3180
+ } = _ref;
3181
+ if (Array.isArray(data) && data.length === 0) {
3182
+ return null;
3183
+ }
3184
+ const groupKeyFn = GROUP_KEY_FN_MAPPING[groupType];
3185
+ if (!groupKeyFn) {
3186
+ return null;
3187
+ }
3188
+ const groups = data.reduce((acc, item) => {
3189
+ const value = item[keysColumn];
3190
+ const formattedValue = new Date(value);
3191
+ const groupKey = groupKeyFn(formattedValue);
3192
+ if (!isNaN(groupKey)) {
3193
+ let groupedValues = acc.get(groupKey);
3194
+ if (!groupedValues) {
3195
+ groupedValues = [];
3196
+ acc.set(groupKey, groupedValues);
3197
+ }
3198
+ const aggregatedValue = aggregate(item, valuesColumns, joinOperation);
3199
+ const isValid = aggregatedValue !== null && aggregatedValue !== undefined;
3200
+ if (isValid) {
3201
+ groupedValues.push(aggregatedValue);
3202
+ acc.set(groupKey, groupedValues);
3203
+ }
3204
+ }
3205
+ return acc;
3206
+ }, new Map());
3207
+ const targetOperation = aggregationFunctions[operation];
3208
+ return [...groups.entries()].map(_ref2 => {
3209
+ let [name, value] = _ref2;
3210
+ return {
3211
+ name,
3212
+ value: targetOperation(value)
3213
+ };
3214
+ }).sort((a, b) => a.name - b.name);
3215
+ }
3216
+
3217
+ /**
3218
+ * Histogram computation.
3219
+ * @privateRemarks Source: @carto/react-core
3220
+ */
3221
+ function histogram(_ref) {
3222
+ let {
3223
+ data,
3224
+ valuesColumns,
3225
+ joinOperation,
3226
+ ticks,
3227
+ operation
3228
+ } = _ref;
3229
+ if (Array.isArray(data) && data.length === 0) {
3230
+ return [];
3231
+ }
3232
+ const binsContainer = [Number.MIN_SAFE_INTEGER, ...ticks].map((tick, index, arr) => ({
3233
+ bin: index,
3234
+ start: tick,
3235
+ end: index === arr.length - 1 ? Number.MAX_SAFE_INTEGER : arr[index + 1],
3236
+ values: []
3237
+ }));
3238
+ data.forEach(feature => {
3239
+ const featureValue = aggregate(feature, valuesColumns, joinOperation);
3240
+ const isValid = featureValue !== null && featureValue !== undefined;
3241
+ if (!isValid) {
3242
+ return;
3243
+ }
3244
+ const binContainer = binsContainer.find(bin => bin.start <= featureValue && bin.end > featureValue);
3245
+ if (!binContainer) {
3246
+ return;
3247
+ }
3248
+ binContainer.values.push(featureValue);
3249
+ });
3250
+ const targetOperation = aggregationFunctions[operation];
3251
+ const transformedBins = binsContainer.map(binContainer => binContainer.values);
3252
+ return transformedBins.map(values => values.length ? targetOperation(values) : 0);
3253
+ }
3254
+
3255
+ /**
3256
+ * Filters invalid features and formats data.
3257
+ * @privateRemarks Source: @carto/react-core
3258
+ */
3259
+ function scatterPlot(_ref) {
3260
+ let {
3261
+ data,
3262
+ xAxisColumns,
3263
+ xAxisJoinOperation,
3264
+ yAxisColumns,
3265
+ yAxisJoinOperation
3266
+ } = _ref;
3267
+ return data.reduce((acc, feature) => {
3268
+ const xValue = aggregate(feature, xAxisColumns, xAxisJoinOperation);
3269
+ const xIsValid = xValue !== null && xValue !== undefined;
3270
+ const yValue = aggregate(feature, yAxisColumns, yAxisJoinOperation);
3271
+ const yIsValid = yValue !== null && yValue !== undefined;
3272
+ if (xIsValid && yIsValid) {
3273
+ acc.push([xValue, yValue]);
3274
+ }
3275
+ return acc;
3276
+ }, []);
3277
+ }
3278
+
3279
+ /**
3280
+ * Source for Widget API requests on a data source defined by a tileset.
3281
+ *
3282
+ * Generally not intended to be constructed directly. Instead, call
3283
+ * {@link vectorTilesetSource}, {@link h3TilesetSource}, or {@link quadbinTilesetSource},
3284
+ * which can be shared with map layers. Sources contain a `widgetSource`
3285
+ * property, for use by widget implementations.
3286
+ *
3287
+ * Example:
3288
+ *
3289
+ * ```javascript
3290
+ * import { vectorTilesetSource } from '@carto/api-client';
3291
+ *
3292
+ * const data = vectorTilesetSource({
3293
+ * accessToken: '••••',
3294
+ * connectionName: 'carto_dw',
3295
+ * tableName: 'carto-demo-data.demo_rasters.my_tileset_source'
3296
+ * });
3297
+ *
3298
+ * const { widgetSource } = await data;
3299
+ * ```
3300
+ */
3301
+ class WidgetTilesetSource extends WidgetSource {
3302
+ constructor() {
3303
+ super(...arguments);
3304
+ this._tiles = [];
3305
+ this._features = [];
3306
+ this._tileFeatureExtractOptions = {};
3307
+ this._tileFeatureExtractPreviousInputs = {};
3308
+ }
3309
+ getModelSource(filters, filterOwner) {
3310
+ return {
3311
+ ...super._getModelSource(filters, filterOwner),
3312
+ type: 'tileset',
3313
+ data: this.props.tableName
3314
+ };
3315
+ }
3316
+ /**
3317
+ * Loads features as a list of tiles (typically provided by deck.gl).
3318
+ * After tiles are loaded, {@link extractTileFeatures} must be called
3319
+ * before computing statistics on the tiles.
3320
+ */
3321
+ loadTiles(tiles) {
3322
+ this._tiles = tiles;
3323
+ this._features.length = 0;
3324
+ }
3325
+ /** Configures options used to extract features from tiles. */
3326
+ setTileFeatureExtractOptions(options) {
3327
+ this._tileFeatureExtractOptions = options;
3328
+ this._features.length = 0;
3329
+ }
3330
+ _extractTileFeatures(spatialFilter) {
3331
+ // When spatial filter has not changed, don't redo extraction. If tiles or
3332
+ // tile extract options change, features will have been cleared already.
3333
+ const prevInputs = this._tileFeatureExtractPreviousInputs;
3334
+ if (this._features.length && prevInputs.spatialFilter && booleanEqual.booleanEqual(prevInputs.spatialFilter, spatialFilter)) {
3335
+ return;
3336
+ }
3337
+ this._features = tileFeatures({
3338
+ tiles: this._tiles,
3339
+ tileFormat: this.props.tileFormat,
3340
+ ...this._tileFeatureExtractOptions,
3341
+ spatialFilter,
3342
+ spatialDataColumn: this.props.spatialDataColumn,
3343
+ spatialDataType: this.props.spatialDataType
3344
+ });
3345
+ prevInputs.spatialFilter = spatialFilter;
3346
+ }
3347
+ /**
3348
+ * Loads features as GeoJSON (used for testing).
3349
+ * @experimental
3350
+ * @internal Not for public use. Spatial filters in other method calls will be ignored.
3351
+ */
3352
+ loadGeoJSON(_ref) {
3353
+ let {
3354
+ geojson,
3355
+ spatialFilter
3356
+ } = _ref;
3357
+ this._features = geojsonFeatures({
3358
+ geojson,
3359
+ spatialFilter,
3360
+ ...this._tileFeatureExtractOptions
3361
+ });
3362
+ this._tileFeatureExtractPreviousInputs.spatialFilter = spatialFilter;
3363
+ }
3364
+ getFeatures() {
3365
+ try {
3366
+ throw new Error('getFeatures not supported for tilesets');
3367
+ return Promise.resolve();
3368
+ } catch (e) {
3369
+ return Promise.reject(e);
3370
+ }
3371
+ }
3372
+ getFormula(_ref2) {
3373
+ let {
3374
+ column = '*',
3375
+ operation = 'count',
3376
+ joinOperation,
3377
+ filters,
3378
+ filterOwner,
3379
+ spatialFilter
3380
+ } = _ref2;
3381
+ try {
3382
+ const _this = this;
3383
+ if (operation === 'custom') {
3384
+ throw new Error('Custom aggregation not supported for tilesets');
3385
+ }
3386
+ // Column is required except when operation is 'count'.
3387
+ if (column && column !== '*' || operation !== 'count') {
3388
+ assertColumn(_this._features, column);
3389
+ }
3390
+ const filteredFeatures = _this._getFilteredFeatures(spatialFilter, filters, filterOwner);
3391
+ if (filteredFeatures.length === 0 && operation !== 'count') {
3392
+ return Promise.resolve({
3393
+ value: null
3394
+ });
3395
+ }
3396
+ const targetOperation = aggregationFunctions[operation];
3397
+ return Promise.resolve({
3398
+ value: targetOperation(filteredFeatures, column, joinOperation)
3399
+ });
3400
+ } catch (e) {
3401
+ return Promise.reject(e);
3402
+ }
3403
+ }
3404
+ getHistogram(_ref3) {
3405
+ let {
3406
+ operation = 'count',
3407
+ ticks,
3408
+ column,
3409
+ joinOperation,
3410
+ filters,
3411
+ filterOwner,
3412
+ spatialFilter
3413
+ } = _ref3;
3414
+ try {
3415
+ const _this2 = this;
3416
+ const filteredFeatures = _this2._getFilteredFeatures(spatialFilter, filters, filterOwner);
3417
+ assertColumn(_this2._features, column);
3418
+ if (!_this2._features.length) {
3419
+ return Promise.resolve([]);
3420
+ }
3421
+ return Promise.resolve(histogram({
3422
+ data: filteredFeatures,
3423
+ valuesColumns: normalizeColumns(column),
3424
+ joinOperation,
3425
+ ticks,
3426
+ operation
3427
+ }));
3428
+ } catch (e) {
3429
+ return Promise.reject(e);
3430
+ }
3431
+ }
3432
+ getCategories(_ref4) {
3433
+ let {
3434
+ column,
3435
+ operation = 'count',
3436
+ operationColumn,
3437
+ joinOperation,
3438
+ filters,
3439
+ filterOwner,
3440
+ spatialFilter
3441
+ } = _ref4;
3442
+ try {
3443
+ const _this3 = this;
3444
+ const filteredFeatures = _this3._getFilteredFeatures(spatialFilter, filters, filterOwner);
3445
+ if (!filteredFeatures.length) {
3446
+ return Promise.resolve([]);
3447
+ }
3448
+ assertColumn(_this3._features, column, operationColumn);
3449
+ const groups = groupValuesByColumn({
3450
+ data: filteredFeatures,
3451
+ valuesColumns: normalizeColumns(operationColumn || column),
3452
+ joinOperation,
3453
+ keysColumn: column,
3454
+ operation
3455
+ });
3456
+ return Promise.resolve(groups || []);
3457
+ } catch (e) {
3458
+ return Promise.reject(e);
3459
+ }
3460
+ }
3461
+ getScatter(_ref5) {
3462
+ let {
3463
+ xAxisColumn,
3464
+ yAxisColumn,
3465
+ xAxisJoinOperation,
3466
+ yAxisJoinOperation,
3467
+ filters,
3468
+ filterOwner,
3469
+ spatialFilter
3470
+ } = _ref5;
3471
+ try {
3472
+ const _this4 = this;
3473
+ const filteredFeatures = _this4._getFilteredFeatures(spatialFilter, filters, filterOwner);
3474
+ if (!filteredFeatures.length) {
3475
+ return Promise.resolve([]);
3476
+ }
3477
+ assertColumn(_this4._features, xAxisColumn, yAxisColumn);
3478
+ return Promise.resolve(scatterPlot({
3479
+ data: filteredFeatures,
3480
+ xAxisColumns: normalizeColumns(xAxisColumn),
3481
+ xAxisJoinOperation,
3482
+ yAxisColumns: normalizeColumns(yAxisColumn),
3483
+ yAxisJoinOperation
3484
+ }));
3485
+ } catch (e) {
3486
+ return Promise.reject(e);
3487
+ }
3488
+ }
3489
+ getTable(_ref6) {
3490
+ let {
3491
+ columns,
3492
+ searchFilterColumn,
3493
+ searchFilterText,
3494
+ sortBy,
3495
+ sortDirection,
3496
+ sortByColumnType,
3497
+ offset = 0,
3498
+ limit = 10,
3499
+ filters,
3500
+ filterOwner,
3501
+ spatialFilter
3502
+ } = _ref6;
3503
+ try {
3504
+ const _this5 = this;
3505
+ // Filter.
3506
+ let filteredFeatures = _this5._getFilteredFeatures(spatialFilter, filters, filterOwner);
3507
+ if (!filteredFeatures.length) {
3508
+ return Promise.resolve({
3509
+ rows: [],
3510
+ totalCount: 0
3511
+ });
3512
+ }
3513
+ // Search.
3514
+ if (searchFilterColumn && searchFilterText) {
3515
+ filteredFeatures = filteredFeatures.filter(row => row[searchFilterColumn] && String(row[searchFilterColumn]).toLowerCase().includes(String(searchFilterText).toLowerCase()));
3516
+ }
3517
+ // Sort.
3518
+ let rows = applySorting(filteredFeatures, {
3519
+ sortBy,
3520
+ sortByDirection: sortDirection,
3521
+ sortByColumnType
3522
+ });
3523
+ const totalCount = rows.length;
3524
+ // Offset and limit.
3525
+ rows = rows.slice(Math.min(offset, totalCount), Math.min(offset + limit, totalCount));
3526
+ // Select columns.
3527
+ rows = rows.map(srcRow => {
3528
+ const dstRow = {};
3529
+ for (const column of columns) {
3530
+ dstRow[column] = srcRow[column];
3531
+ }
3532
+ return dstRow;
3533
+ });
3534
+ return Promise.resolve({
3535
+ rows,
3536
+ totalCount
3537
+ });
3538
+ } catch (e) {
3539
+ return Promise.reject(e);
3540
+ }
3541
+ }
3542
+ getTimeSeries(_ref7) {
3543
+ let {
3544
+ column,
3545
+ stepSize,
3546
+ operation,
3547
+ operationColumn,
3548
+ joinOperation,
3549
+ filters,
3550
+ filterOwner,
3551
+ spatialFilter
3552
+ } = _ref7;
3553
+ try {
3554
+ const _this6 = this;
3555
+ const filteredFeatures = _this6._getFilteredFeatures(spatialFilter, filters, filterOwner);
3556
+ if (!filteredFeatures.length) {
3557
+ return Promise.resolve({
3558
+ rows: []
3559
+ });
3560
+ }
3561
+ assertColumn(_this6._features, column, operationColumn);
3562
+ const rows = groupValuesByDateColumn({
3563
+ data: filteredFeatures,
3564
+ valuesColumns: normalizeColumns(operationColumn || column),
3565
+ keysColumn: column,
3566
+ groupType: stepSize,
3567
+ operation,
3568
+ joinOperation
3569
+ }) || [];
3570
+ return Promise.resolve({
3571
+ rows
3572
+ });
3573
+ } catch (e) {
3574
+ return Promise.reject(e);
3575
+ }
3576
+ }
3577
+ getRange(_ref8) {
3578
+ let {
3579
+ column,
3580
+ filters,
3581
+ filterOwner,
3582
+ spatialFilter
3583
+ } = _ref8;
3584
+ try {
3585
+ const _this7 = this;
3586
+ assertColumn(_this7._features, column);
3587
+ const filteredFeatures = _this7._getFilteredFeatures(spatialFilter, filters, filterOwner);
3588
+ if (!_this7._features.length) {
3589
+ // TODO: Is this the only nullable response in the Widgets API? If so,
3590
+ // can we do something more consistent?
3591
+ return Promise.resolve(null);
3592
+ }
3593
+ return Promise.resolve({
3594
+ min: aggregationFunctions.min(filteredFeatures, column),
3595
+ max: aggregationFunctions.max(filteredFeatures, column)
3596
+ });
3597
+ } catch (e) {
3598
+ return Promise.reject(e);
3599
+ }
3600
+ }
3601
+ /****************************************************************************
3602
+ * INTERNAL
3603
+ */
3604
+ _getFilteredFeatures(spatialFilter, filters, filterOwner) {
3605
+ assert(spatialFilter, 'spatialFilter required for tilesets');
3606
+ this._extractTileFeatures(spatialFilter);
3607
+ return applyFilters(this._features, getApplicableFilters(filterOwner, filters || this.props.filters), this.props.filtersLogicalOperator || 'and');
3608
+ }
3609
+ }
3610
+ function assertColumn(features) {
3611
+ // TODO(cleanup): Can drop support for multiple column shapes here?
3612
+ // Due to the multiple column shape, we normalise it as an array with normalizeColumns
3613
+ const columns = Array.from(new Set([].slice.call(arguments, 1).map(normalizeColumns).flat()));
3614
+ const featureKeys = Object.keys(features[0]);
3615
+ const invalidColumns = columns.filter(column => !featureKeys.includes(column));
3616
+ if (invalidColumns.length) {
3617
+ throw new InvalidColumnError(`Missing column(s): ${invalidColumns.join(', ')}`);
3618
+ }
3619
+ }
3620
+ function normalizeColumns(columns) {
3621
+ return Array.isArray(columns) ? columns : typeof columns === 'string' ? [columns] : [];
3622
+ }
3623
+
1553
3624
  // deck.gl
1554
3625
  // SPDX-License-Identifier: MIT
1555
3626
  // Copyright (c) vis.gl contributors
1556
- /* eslint-disable camelcase */
1557
3627
  const h3QuerySource = function (options) {
1558
3628
  try {
1559
3629
  const {
@@ -1597,7 +3667,6 @@ const h3QuerySource = function (options) {
1597
3667
  // deck.gl
1598
3668
  // SPDX-License-Identifier: MIT
1599
3669
  // Copyright (c) vis.gl contributors
1600
- /* eslint-disable camelcase */
1601
3670
  const h3TableSource = function (options) {
1602
3671
  try {
1603
3672
  const {
@@ -1675,7 +3744,6 @@ const rasterSource = function (options) {
1675
3744
  // deck.gl
1676
3745
  // SPDX-License-Identifier: MIT
1677
3746
  // Copyright (c) vis.gl contributors
1678
- /* eslint-disable camelcase */
1679
3747
  const quadbinQuerySource = function (options) {
1680
3748
  try {
1681
3749
  const {
@@ -1719,7 +3787,6 @@ const quadbinQuerySource = function (options) {
1719
3787
  // deck.gl
1720
3788
  // SPDX-License-Identifier: MIT
1721
3789
  // Copyright (c) vis.gl contributors
1722
- /* eslint-disable camelcase */
1723
3790
  const quadbinTableSource = function (options) {
1724
3791
  try {
1725
3792
  const {
@@ -1776,13 +3843,12 @@ const quadbinTilesetSource = function (options) {
1776
3843
  // deck.gl
1777
3844
  // SPDX-License-Identifier: MIT
1778
3845
  // Copyright (c) vis.gl contributors
1779
- /* eslint-disable camelcase */
1780
3846
  const vectorQuerySource = function (options) {
1781
3847
  try {
1782
3848
  const {
1783
3849
  columns,
1784
3850
  filters,
1785
- spatialDataColumn = 'geom',
3851
+ spatialDataColumn = DEFAULT_GEO_COLUMN,
1786
3852
  sqlQuery,
1787
3853
  tileResolution = DEFAULT_TILE_RESOLUTION,
1788
3854
  queryParameters,
@@ -1825,13 +3891,12 @@ const vectorQuerySource = function (options) {
1825
3891
  // deck.gl
1826
3892
  // SPDX-License-Identifier: MIT
1827
3893
  // Copyright (c) vis.gl contributors
1828
- /* eslint-disable camelcase */
1829
3894
  const vectorTableSource = function (options) {
1830
3895
  try {
1831
3896
  const {
1832
3897
  columns,
1833
3898
  filters,
1834
- spatialDataColumn = 'geom',
3899
+ spatialDataColumn = DEFAULT_GEO_COLUMN,
1835
3900
  tableName,
1836
3901
  tileResolution = DEFAULT_TILE_RESOLUTION,
1837
3902
  aggregationExp
@@ -1937,25 +4002,41 @@ const query = function (options) {
1937
4002
 
1938
4003
  exports.CartoAPIError = CartoAPIError;
1939
4004
  exports.DEFAULT_API_BASE_URL = DEFAULT_API_BASE_URL;
4005
+ exports.FEATURE_GEOM_PROPERTY = FEATURE_GEOM_PROPERTY;
1940
4006
  exports.SOURCE_DEFAULTS = SOURCE_DEFAULTS;
1941
- exports.WidgetBaseSource = WidgetBaseSource;
1942
4007
  exports.WidgetQuerySource = WidgetQuerySource;
4008
+ exports.WidgetRemoteSource = WidgetRemoteSource;
4009
+ exports.WidgetSource = WidgetSource;
1943
4010
  exports.WidgetTableSource = WidgetTableSource;
4011
+ exports.WidgetTilesetSource = WidgetTilesetSource;
4012
+ exports._buildFeatureFilter = _buildFeatureFilter;
1944
4013
  exports._getHexagonResolution = _getHexagonResolution;
1945
4014
  exports.addFilter = addFilter;
4015
+ exports.aggregate = aggregate;
4016
+ exports.aggregationFunctions = aggregationFunctions;
4017
+ exports.applyFilters = applyFilters;
4018
+ exports.applySorting = applySorting;
1946
4019
  exports.boundaryQuerySource = boundaryQuerySource;
1947
4020
  exports.boundaryTableSource = boundaryTableSource;
4021
+ exports.buildBinaryFeatureFilter = buildBinaryFeatureFilter;
1948
4022
  exports.buildPublicMapUrl = buildPublicMapUrl;
1949
4023
  exports.buildStatsUrl = buildStatsUrl;
1950
4024
  exports.clearFilters = clearFilters;
1951
4025
  exports.createPolygonSpatialFilter = createPolygonSpatialFilter;
1952
4026
  exports.createViewportSpatialFilter = createViewportSpatialFilter;
4027
+ exports.filterFunctions = filterFunctions;
4028
+ exports.geojsonFeatures = geojsonFeatures;
1953
4029
  exports.getClient = getClient;
4030
+ exports.getDataFilterExtensionProps = getDataFilterExtensionProps;
1954
4031
  exports.getFilter = getFilter;
4032
+ exports.groupValuesByColumn = groupValuesByColumn;
4033
+ exports.groupValuesByDateColumn = groupValuesByDateColumn;
1955
4034
  exports.h3QuerySource = h3QuerySource;
1956
4035
  exports.h3TableSource = h3TableSource;
1957
4036
  exports.h3TilesetSource = h3TilesetSource;
1958
4037
  exports.hasFilter = hasFilter;
4038
+ exports.histogram = histogram;
4039
+ exports.makeIntervalComplete = makeIntervalComplete;
1959
4040
  exports.quadbinQuerySource = quadbinQuerySource;
1960
4041
  exports.quadbinTableSource = quadbinTableSource;
1961
4042
  exports.quadbinTilesetSource = quadbinTilesetSource;
@@ -1963,7 +4044,12 @@ exports.query = query;
1963
4044
  exports.rasterSource = rasterSource;
1964
4045
  exports.removeFilter = removeFilter;
1965
4046
  exports.requestWithParameters = requestWithParameters;
4047
+ exports.scatterPlot = scatterPlot;
1966
4048
  exports.setClient = setClient;
4049
+ exports.tileFeatures = tileFeatures;
4050
+ exports.tileFeaturesGeometries = tileFeaturesGeometries;
4051
+ exports.tileFeaturesSpatialIndex = tileFeaturesSpatialIndex;
4052
+ exports.transformToTileCoords = transformToTileCoords;
1967
4053
  exports.vectorQuerySource = vectorQuerySource;
1968
4054
  exports.vectorTableSource = vectorTableSource;
1969
4055
  exports.vectorTilesetSource = vectorTilesetSource;