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

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