@carto/api-client 0.4.4 → 0.5.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/build/api-client.cjs +2223 -240
  2. package/build/api-client.cjs.map +1 -1
  3. package/build/api-client.modern.js +2075 -237
  4. package/build/api-client.modern.js.map +1 -1
  5. package/build/constants.d.ts +22 -0
  6. package/build/filters/Filter.d.ts +13 -0
  7. package/build/filters/FilterTypes.d.ts +3 -0
  8. package/build/filters/geosjonFeatures.d.ts +8 -0
  9. package/build/filters/index.d.ts +6 -0
  10. package/build/filters/tileFeatures.d.ts +20 -0
  11. package/build/filters/tileFeaturesGeometries.d.ts +13 -0
  12. package/build/filters/tileFeaturesSpatialIndex.d.ts +10 -0
  13. package/build/index.d.ts +4 -0
  14. package/build/models/index.d.ts +1 -1
  15. package/build/operations/aggregation.d.ts +8 -0
  16. package/build/operations/applySorting.d.ts +20 -0
  17. package/build/operations/groupBy.d.ts +15 -0
  18. package/build/operations/groupByDate.d.ts +11 -0
  19. package/build/operations/histogram.d.ts +13 -0
  20. package/build/operations/index.d.ts +6 -0
  21. package/build/operations/scatterPlot.d.ts +14 -0
  22. package/build/sources/h3-tileset-source.d.ts +2 -1
  23. package/build/sources/index.d.ts +1 -1
  24. package/build/sources/quadbin-tileset-source.d.ts +2 -1
  25. package/build/sources/vector-tileset-source.d.ts +2 -1
  26. package/build/types-internal.d.ts +4 -0
  27. package/build/types.d.ts +61 -1
  28. package/build/utils/dateUtils.d.ts +10 -0
  29. package/build/utils/getTileFormat.d.ts +3 -0
  30. package/build/utils/makeIntervalComplete.d.ts +2 -0
  31. package/build/utils/transformTileCoordsToWGS84.d.ts +8 -0
  32. package/build/utils/transformToTileCoords.d.ts +9 -0
  33. package/build/widget-sources/index.d.ts +2 -1
  34. package/build/widget-sources/types.d.ts +31 -22
  35. package/build/widget-sources/widget-query-source.d.ts +2 -2
  36. package/build/widget-sources/widget-remote-source.d.ts +18 -0
  37. package/build/widget-sources/{widget-base-source.d.ts → widget-source.d.ts} +13 -38
  38. package/build/widget-sources/widget-table-source.d.ts +2 -2
  39. package/build/widget-sources/widget-tileset-source.d.ts +67 -0
  40. package/package.json +36 -35
  41. package/src/constants.ts +25 -0
  42. package/src/filters/Filter.ts +169 -0
  43. package/src/filters/FilterTypes.ts +109 -0
  44. package/src/filters/geosjonFeatures.ts +32 -0
  45. package/src/filters/index.ts +6 -0
  46. package/src/filters/tileFeatures.ts +56 -0
  47. package/src/filters/tileFeaturesGeometries.ts +444 -0
  48. package/src/filters/tileFeaturesSpatialIndex.ts +119 -0
  49. package/src/index.ts +6 -0
  50. package/src/models/index.ts +1 -1
  51. package/src/operations/aggregation.ts +154 -0
  52. package/src/operations/applySorting.ts +109 -0
  53. package/src/operations/groupBy.ts +59 -0
  54. package/src/operations/groupByDate.ts +98 -0
  55. package/src/operations/histogram.ts +66 -0
  56. package/src/operations/index.ts +6 -0
  57. package/src/operations/scatterPlot.ts +50 -0
  58. package/src/sources/h3-tileset-source.ts +18 -6
  59. package/src/sources/index.ts +1 -1
  60. package/src/sources/quadbin-tileset-source.ts +18 -6
  61. package/src/sources/raster-source.ts +1 -0
  62. package/src/sources/vector-query-source.ts +6 -2
  63. package/src/sources/vector-table-source.ts +6 -2
  64. package/src/sources/vector-tileset-source.ts +19 -6
  65. package/src/types-internal.ts +6 -0
  66. package/src/types.ts +60 -2
  67. package/src/utils/dateUtils.ts +28 -0
  68. package/src/utils/getTileFormat.ts +9 -0
  69. package/src/utils/makeIntervalComplete.ts +17 -0
  70. package/src/utils/transformTileCoordsToWGS84.ts +77 -0
  71. package/src/utils/transformToTileCoords.ts +85 -0
  72. package/src/utils.ts +8 -5
  73. package/src/widget-sources/index.ts +2 -1
  74. package/src/widget-sources/types.ts +32 -22
  75. package/src/widget-sources/widget-query-source.ts +6 -3
  76. package/src/widget-sources/{widget-base-source.ts → widget-remote-source.ts} +12 -147
  77. package/src/widget-sources/widget-source.ts +160 -0
  78. package/src/widget-sources/widget-table-source.ts +6 -3
  79. package/src/widget-sources/widget-tileset-source.ts +396 -0
@@ -3,6 +3,10 @@ import bboxPolygon from '@turf/bbox-polygon';
3
3
  import union from '@turf/union';
4
4
  import { getType } from '@turf/invariant';
5
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$2, polygonToCells } from 'h3-js';
6
10
 
7
11
  /**
8
12
  * @internal
@@ -61,6 +65,31 @@ var ApiVersion;
61
65
  })(ApiVersion || (ApiVersion = {}));
62
66
  /** @internalRemarks Source: @carto/constants, @deck.gl/carto */
63
67
  const DEFAULT_API_BASE_URL = 'https://gcp-us-east1.api.carto.com';
68
+ /** @internalRemarks Source: @carto/react-core */
69
+ var TileFormat;
70
+ (function (TileFormat) {
71
+ TileFormat["MVT"] = "mvt";
72
+ TileFormat["JSON"] = "json";
73
+ TileFormat["GEOJSON"] = "geojson";
74
+ TileFormat["BINARY"] = "binary";
75
+ })(TileFormat || (TileFormat = {}));
76
+ /** @internalRemarks Source: @carto/react-core */
77
+ var SpatialIndex;
78
+ (function (SpatialIndex) {
79
+ SpatialIndex["H3"] = "h3";
80
+ SpatialIndex["S2"] = "s2";
81
+ SpatialIndex["QUADBIN"] = "quadbin";
82
+ })(SpatialIndex || (SpatialIndex = {}));
83
+ /** @internalRemarks Source: @carto/react-core */
84
+ var Provider;
85
+ (function (Provider) {
86
+ Provider["BIGQUERY"] = "bigquery";
87
+ Provider["REDSHIFT"] = "redshift";
88
+ Provider["POSTGRES"] = "postgres";
89
+ Provider["SNOWFLAKE"] = "snowflake";
90
+ Provider["DATABRICKS"] = "databricks";
91
+ Provider["DATABRICKS_REST"] = "databricksRest";
92
+ })(Provider || (Provider = {}));
64
93
 
65
94
  const FILTER_TYPES = new Set(Object.values(FilterType));
66
95
  const isFilterType = type => FILTER_TYPES.has(type);
@@ -103,7 +132,7 @@ function normalizeObjectKeys(el) {
103
132
  }, {});
104
133
  }
105
134
  /** @internalRemarks Source: @carto/react-core */
106
- function assert(condition, message) {
135
+ function assert$1(condition, message) {
107
136
  if (!condition) {
108
137
  throw new Error(message);
109
138
  }
@@ -606,7 +635,7 @@ function excludeURLParameters(baseUrlString, parameters) {
606
635
  return baseUrl.toString();
607
636
  }
608
637
 
609
- const _excluded$1 = ["accessToken", "connectionName", "cache"];
638
+ const _excluded$2 = ["accessToken", "connectionName", "cache"];
610
639
  const SOURCE_DEFAULTS = {
611
640
  apiBaseUrl: DEFAULT_API_BASE_URL,
612
641
  clientId: getClient(),
@@ -620,7 +649,7 @@ async function baseSource(endpoint, options, urlParameters) {
620
649
  connectionName,
621
650
  cache
622
651
  } = options,
623
- optionalOptions = _objectWithoutPropertiesLoose(options, _excluded$1);
652
+ optionalOptions = _objectWithoutPropertiesLoose(options, _excluded$2);
624
653
  const mergedOptions = _extends({}, SOURCE_DEFAULTS, {
625
654
  accessToken,
626
655
  connectionName,
@@ -686,6 +715,8 @@ async function baseSource(endpoint, options, urlParameters) {
686
715
  }
687
716
 
688
717
  // deck.gl
718
+ // SPDX-License-Identifier: MIT
719
+ // Copyright (c) vis.gl contributors
689
720
  const boundaryQuerySource = async function boundaryQuerySource(options) {
690
721
  const {
691
722
  columns,
@@ -711,6 +742,8 @@ const boundaryQuerySource = async function boundaryQuerySource(options) {
711
742
  };
712
743
 
713
744
  // deck.gl
745
+ // SPDX-License-Identifier: MIT
746
+ // Copyright (c) vis.gl contributors
714
747
  const boundaryTableSource = async function boundaryTableSource(options) {
715
748
  const {
716
749
  filters,
@@ -804,10 +837,10 @@ const REQUEST_GET_MAX_URL_LENGTH = 2048;
804
837
  * @internalRemarks Source: @carto/react-api
805
838
  */
806
839
  function executeModel(props) {
807
- assert(props.source, 'executeModel: missing source');
808
- assert(props.model, 'executeModel: missing model');
809
- assert(props.params, 'executeModel: missing params');
810
- assert(AVAILABLE_MODELS.includes(props.model), `executeModel: model provided isn't valid. Available models: ${AVAILABLE_MODELS.join(', ')}`);
840
+ assert$1(props.source, 'executeModel: missing source');
841
+ assert$1(props.model, 'executeModel: missing model');
842
+ assert$1(props.params, 'executeModel: missing params');
843
+ assert$1(AVAILABLE_MODELS.includes(props.model), `executeModel: model provided isn't valid. Available models: ${AVAILABLE_MODELS.join(', ')}`);
811
844
  const {
812
845
  model,
813
846
  source,
@@ -822,10 +855,10 @@ function executeModel(props) {
822
855
  connectionName,
823
856
  clientId
824
857
  } = source;
825
- assert(apiBaseUrl, 'executeModel: missing apiBaseUrl');
826
- assert(accessToken, 'executeModel: missing accessToken');
827
- assert(apiVersion === V3, 'executeModel: SQL Model API requires CARTO 3+');
828
- assert(type !== 'tileset', 'executeModel: Tilesets not supported');
858
+ assert$1(apiBaseUrl, 'executeModel: missing apiBaseUrl');
859
+ assert$1(accessToken, 'executeModel: missing accessToken');
860
+ assert$1(apiVersion === V3, 'executeModel: SQL Model API requires CARTO 3+');
861
+ assert$1(type !== 'tileset', 'executeModel: Tilesets not supported');
829
862
  let url = `${apiBaseUrl}/v3/sql/${connectionName}/model/${model}`;
830
863
  const {
831
864
  data,
@@ -936,23 +969,15 @@ function getHexagonResolution(viewport, tileSize) {
936
969
  return Math.max(0, Math.floor(hexagonScaleFactor + latitudeScaleFactor - BIAS));
937
970
  }
938
971
 
939
- const _excluded = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
940
- _excluded2 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
941
- _excluded3 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController", "operationExp"],
942
- _excluded4 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
943
- _excluded5 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
944
- _excluded6 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
945
- _excluded7 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
946
- _excluded8 = ["filterOwner", "abortController", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState"];
947
972
  /**
948
973
  * Source for Widget API requests on a data source defined by a SQL query.
949
974
  *
950
975
  * Abstract class. Use {@link WidgetQuerySource} or {@link WidgetTableSource}.
951
976
  */
952
- class WidgetBaseSource {
977
+ class WidgetSource {
953
978
  constructor(props) {
954
979
  this.props = void 0;
955
- this.props = _extends({}, WidgetBaseSource.defaultProps, props);
980
+ this.props = _extends({}, WidgetSource.defaultProps, props);
956
981
  }
957
982
  _getModelSource(owner) {
958
983
  const props = this.props;
@@ -979,13 +1004,29 @@ class WidgetBaseSource {
979
1004
  }
980
1005
  return getSpatialFiltersResolution(source, referenceViewState);
981
1006
  }
982
- /****************************************************************************
983
- * CATEGORIES
984
- */
985
- /**
986
- * Returns a list of labeled datapoints for categorical data. Suitable for
987
- * charts including grouped bar charts, pie charts, and tree charts.
988
- */
1007
+ }
1008
+ WidgetSource.defaultProps = {
1009
+ apiVersion: ApiVersion.V3,
1010
+ apiBaseUrl: DEFAULT_API_BASE_URL,
1011
+ clientId: getClient(),
1012
+ filters: {},
1013
+ filtersLogicalOperator: 'and'
1014
+ };
1015
+
1016
+ const _excluded$1 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
1017
+ _excluded2 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
1018
+ _excluded3 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController", "operationExp"],
1019
+ _excluded4 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
1020
+ _excluded5 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
1021
+ _excluded6 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
1022
+ _excluded7 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
1023
+ _excluded8 = ["filterOwner", "abortController", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState"];
1024
+ /**
1025
+ * Source for Widget API requests.
1026
+ *
1027
+ * Abstract class. Use {@link WidgetQuerySource} or {@link WidgetTableSource}.
1028
+ */
1029
+ class WidgetRemoteSource extends WidgetSource {
989
1030
  async getCategories(options) {
990
1031
  const {
991
1032
  filterOwner,
@@ -994,7 +1035,7 @@ class WidgetBaseSource {
994
1035
  spatialIndexReferenceViewState,
995
1036
  abortController
996
1037
  } = options,
997
- params = _objectWithoutPropertiesLoose(options, _excluded);
1038
+ params = _objectWithoutPropertiesLoose(options, _excluded$1);
998
1039
  const {
999
1040
  column,
1000
1041
  operation,
@@ -1019,17 +1060,6 @@ class WidgetBaseSource {
1019
1060
  }
1020
1061
  }).then(res => normalizeObjectKeys(res.rows));
1021
1062
  }
1022
- /****************************************************************************
1023
- * FEATURES
1024
- */
1025
- /**
1026
- * Given a list of feature IDs (as found in `_carto_feature_id`) returns all
1027
- * matching features. In datasets containing features with duplicate geometries,
1028
- * feature IDs may be duplicated (IDs are a hash of geometry) and so more
1029
- * results may be returned than IDs in the request.
1030
- * @internal
1031
- * @experimental
1032
- */
1033
1063
  async getFeatures(options) {
1034
1064
  const {
1035
1065
  filterOwner,
@@ -1074,13 +1104,6 @@ class WidgetBaseSource {
1074
1104
  rows
1075
1105
  }));
1076
1106
  }
1077
- /****************************************************************************
1078
- * FORMULA
1079
- */
1080
- /**
1081
- * Returns a scalar numerical statistic over all matching data. Suitable
1082
- * for 'headline' or 'scorecard' figures such as counts and sums.
1083
- */
1084
1107
  async getFormula(options) {
1085
1108
  const {
1086
1109
  filterOwner,
@@ -1106,7 +1129,7 @@ class WidgetBaseSource {
1106
1129
  }),
1107
1130
  params: {
1108
1131
  column: column != null ? column : '*',
1109
- operation,
1132
+ operation: operation != null ? operation : 'count',
1110
1133
  operationExp
1111
1134
  },
1112
1135
  opts: {
@@ -1114,13 +1137,6 @@ class WidgetBaseSource {
1114
1137
  }
1115
1138
  }).then(res => normalizeObjectKeys(res.rows[0]));
1116
1139
  }
1117
- /****************************************************************************
1118
- * HISTOGRAM
1119
- */
1120
- /**
1121
- * Returns a list of labeled datapoints for 'bins' of data defined as ticks
1122
- * over a numerical range. Suitable for histogram charts.
1123
- */
1124
1140
  async getHistogram(options) {
1125
1141
  const {
1126
1142
  filterOwner,
@@ -1165,14 +1181,6 @@ class WidgetBaseSource {
1165
1181
  }
1166
1182
  return [];
1167
1183
  }
1168
- /****************************************************************************
1169
- * RANGE
1170
- */
1171
- /**
1172
- * Returns a range (min and max) for a numerical column of matching rows.
1173
- * Suitable for displaying certain 'headline' or 'scorecard' statistics,
1174
- * or rendering a range slider UI for filtering.
1175
- */
1176
1184
  async getRange(options) {
1177
1185
  const {
1178
1186
  filterOwner,
@@ -1202,13 +1210,6 @@ class WidgetBaseSource {
1202
1210
  }
1203
1211
  }).then(res => normalizeObjectKeys(res.rows[0]));
1204
1212
  }
1205
- /****************************************************************************
1206
- * SCATTER
1207
- */
1208
- /**
1209
- * Returns a list of bivariate datapoints defined as numerical 'x' and 'y'
1210
- * values. Suitable for rendering scatter plots.
1211
- */
1212
1213
  async getScatter(options) {
1213
1214
  const {
1214
1215
  filterOwner,
@@ -1250,13 +1251,6 @@ class WidgetBaseSource {
1250
1251
  y
1251
1252
  }) => [x, y]));
1252
1253
  }
1253
- /****************************************************************************
1254
- * TABLE
1255
- */
1256
- /**
1257
- * Returns a list of arbitrary data rows, with support for pagination and
1258
- * sorting. Suitable for displaying tables and lists.
1259
- */
1260
1254
  async getTable(options) {
1261
1255
  const {
1262
1256
  filterOwner,
@@ -1301,13 +1295,6 @@ class WidgetBaseSource {
1301
1295
  };
1302
1296
  });
1303
1297
  }
1304
- /****************************************************************************
1305
- * TIME SERIES
1306
- */
1307
- /**
1308
- * Returns a series of labeled numerical values, grouped into equally-sized
1309
- * time intervals. Suitable for rendering time series charts.
1310
- */
1311
1298
  async getTimeSeries(options) {
1312
1299
  const {
1313
1300
  filterOwner,
@@ -1360,13 +1347,6 @@ class WidgetBaseSource {
1360
1347
  });
1361
1348
  }
1362
1349
  }
1363
- WidgetBaseSource.defaultProps = {
1364
- apiVersion: ApiVersion.V3,
1365
- apiBaseUrl: DEFAULT_API_BASE_URL,
1366
- clientId: getClient(),
1367
- filters: {},
1368
- filtersLogicalOperator: 'and'
1369
- };
1370
1350
 
1371
1351
  /**
1372
1352
  * Source for Widget API requests on a data source defined by a SQL query.
@@ -1390,7 +1370,7 @@ WidgetBaseSource.defaultProps = {
1390
1370
  * const { widgetSource } = await data;
1391
1371
  * ```
1392
1372
  */
1393
- class WidgetQuerySource extends WidgetBaseSource {
1373
+ class WidgetQuerySource extends WidgetRemoteSource {
1394
1374
  getModelSource(owner) {
1395
1375
  return _extends({}, super._getModelSource(owner), {
1396
1376
  type: 'query',
@@ -1422,7 +1402,7 @@ class WidgetQuerySource extends WidgetBaseSource {
1422
1402
  * const { widgetSource } = await data;
1423
1403
  * ```
1424
1404
  */
1425
- class WidgetTableSource extends WidgetBaseSource {
1405
+ class WidgetTableSource extends WidgetRemoteSource {
1426
1406
  getModelSource(owner) {
1427
1407
  return _extends({}, super._getModelSource(owner), {
1428
1408
  type: 'table',
@@ -1431,172 +1411,2022 @@ class WidgetTableSource extends WidgetBaseSource {
1431
1411
  }
1432
1412
  }
1433
1413
 
1434
- const h3QuerySource = async function h3QuerySource(options) {
1435
- const {
1436
- aggregationExp,
1437
- aggregationResLevel = DEFAULT_AGGREGATION_RES_LEVEL_H3,
1438
- sqlQuery,
1439
- spatialDataColumn = 'h3',
1440
- queryParameters,
1441
- filters
1442
- } = options;
1443
- const urlParameters = {
1444
- aggregationExp,
1445
- spatialDataColumn,
1446
- spatialDataType: 'h3',
1447
- q: sqlQuery
1448
- };
1449
- if (aggregationResLevel) {
1450
- urlParameters.aggregationResLevel = String(aggregationResLevel);
1451
- }
1452
- if (queryParameters) {
1453
- urlParameters.queryParameters = queryParameters;
1454
- }
1455
- if (filters) {
1456
- urlParameters.filters = filters;
1457
- }
1458
- return baseSource('query', options, urlParameters).then(result => _extends({}, result, {
1459
- widgetSource: new WidgetQuerySource(_extends({}, options, {
1460
- // NOTE: passing redundant spatialDataColumn here to apply the default value 'h3'
1461
- spatialDataColumn,
1462
- spatialDataType: 'h3'
1463
- }))
1464
- }));
1465
- };
1414
+ function makeIntervalComplete(intervals) {
1415
+ return intervals.map(val => {
1416
+ if (val[0] === undefined || val[0] === null) {
1417
+ return [Number.MIN_SAFE_INTEGER, val[1]];
1418
+ }
1419
+ if (val[1] === undefined || val[1] === null) {
1420
+ return [val[0], Number.MAX_SAFE_INTEGER];
1421
+ }
1422
+ return val;
1423
+ });
1424
+ }
1466
1425
 
1467
- const h3TableSource = async function h3TableSource(options) {
1468
- const {
1469
- aggregationExp,
1470
- aggregationResLevel = DEFAULT_AGGREGATION_RES_LEVEL_H3,
1471
- spatialDataColumn = 'h3',
1472
- tableName,
1473
- filters
1474
- } = options;
1475
- const urlParameters = {
1476
- aggregationExp,
1477
- name: tableName,
1478
- spatialDataColumn,
1479
- spatialDataType: 'h3'
1426
+ const filterFunctions = {
1427
+ [FilterType.IN]: filterIn,
1428
+ [FilterType.BETWEEN]: filterBetween,
1429
+ [FilterType.TIME]: filterTime,
1430
+ [FilterType.CLOSED_OPEN]: filterClosedOpen,
1431
+ [FilterType.STRING_SEARCH]: filterStringSearch
1432
+ };
1433
+ function filterIn(filterValues, featureValue) {
1434
+ return filterValues.includes(featureValue);
1435
+ }
1436
+ // FilterTypes.BETWEEN
1437
+ function filterBetween(filterValues, featureValue) {
1438
+ const checkRange = range => {
1439
+ const [lowerBound, upperBound] = range;
1440
+ return featureValue >= lowerBound && featureValue <= upperBound;
1480
1441
  };
1481
- if (aggregationResLevel) {
1482
- urlParameters.aggregationResLevel = String(aggregationResLevel);
1483
- }
1484
- if (filters) {
1485
- urlParameters.filters = filters;
1442
+ return makeIntervalComplete(filterValues).some(checkRange);
1443
+ }
1444
+ function filterTime(filterValues, featureValue) {
1445
+ const featureValueAsTimestamp = new Date(featureValue).getTime();
1446
+ if (isFinite(featureValueAsTimestamp)) {
1447
+ return filterBetween(filterValues, featureValueAsTimestamp);
1448
+ } else {
1449
+ throw new Error(`Column used to filter by time isn't well formatted.`);
1486
1450
  }
1487
- return baseSource('table', options, urlParameters).then(result => _extends({}, result, {
1488
- widgetSource: new WidgetTableSource(_extends({}, options, {
1489
- // NOTE: passing redundant spatialDataColumn here to apply the default value 'h3'
1490
- spatialDataColumn,
1491
- spatialDataType: 'h3'
1492
- }))
1493
- }));
1494
- };
1495
-
1496
- // deck.gl
1497
- const h3TilesetSource = async function h3TilesetSource(options) {
1498
- const {
1499
- tableName
1500
- } = options;
1501
- const urlParameters = {
1502
- name: tableName
1451
+ }
1452
+ // FilterTypes.CLOSED_OPEN
1453
+ function filterClosedOpen(filterValues, featureValue) {
1454
+ const checkRange = range => {
1455
+ const [lowerBound, upperBound] = range;
1456
+ return featureValue >= lowerBound && featureValue < upperBound;
1503
1457
  };
1504
- return baseSource('tileset', options, urlParameters);
1505
- };
1458
+ return makeIntervalComplete(filterValues).some(checkRange);
1459
+ }
1460
+ // FilterTypes.STRING_SEARCH
1461
+ function filterStringSearch(filterValues, featureValue, params = {}) {
1462
+ const normalizedFeatureValue = normalize(featureValue, params);
1463
+ const stringRegExp = params.useRegExp ? filterValues : filterValues.map(filterValue => {
1464
+ let stringRegExp = escapeRegExp(normalize(filterValue, params));
1465
+ if (params.mustStart) stringRegExp = `^${stringRegExp}`;
1466
+ if (params.mustEnd) stringRegExp = `${stringRegExp}$`;
1467
+ return stringRegExp;
1468
+ });
1469
+ const regex = new RegExp(stringRegExp.join('|'), params.caseSensitive ? 'g' : 'gi');
1470
+ return !!normalizedFeatureValue.match(regex);
1471
+ }
1472
+ // Aux
1473
+ const specialCharRegExp = /[.*+?^${}()|[\]\\]/g;
1474
+ 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;
1475
+ function escapeRegExp(value) {
1476
+ return value.replace(specialCharRegExp, '\\$&');
1477
+ }
1478
+ function normalize(data, params) {
1479
+ let normalizedData = String(data);
1480
+ if (!params.keepSpecialCharacters) normalizedData = normalizedData.normalize('NFD').replace(normalizeRegExp, '');
1481
+ return normalizedData;
1482
+ }
1506
1483
 
1507
- // deck.gl
1508
- const rasterSource = async function rasterSource(options) {
1509
- const {
1510
- tableName,
1511
- filters
1512
- } = options;
1513
- const urlParameters = {
1514
- name: tableName
1484
+ const LOGICAL_OPERATOR_METHODS = {
1485
+ and: 'every',
1486
+ or: 'some'
1487
+ };
1488
+ function passesFilter(columns, filters, feature, filtersLogicalOperator) {
1489
+ const method = LOGICAL_OPERATOR_METHODS[filtersLogicalOperator];
1490
+ return columns[method](column => {
1491
+ const columnFilters = filters[column];
1492
+ const columnFilterTypes = Object.keys(columnFilters);
1493
+ if (!feature || feature[column] === null || feature[column] === undefined) {
1494
+ return false;
1495
+ }
1496
+ return columnFilterTypes.every(filter => {
1497
+ const filterFunction = filterFunctions[filter];
1498
+ if (!filterFunction) {
1499
+ throw new Error(`"${filter}" filter is not implemented.`);
1500
+ }
1501
+ return filterFunction(columnFilters[filter].values, feature[column], columnFilters[filter].params);
1502
+ });
1503
+ });
1504
+ }
1505
+ function buildFeatureFilter({
1506
+ filters = {},
1507
+ type = 'boolean',
1508
+ filtersLogicalOperator = 'and'
1509
+ }) {
1510
+ const columns = Object.keys(filters);
1511
+ if (!columns.length) {
1512
+ return () => type === 'number' ? 1 : true;
1513
+ }
1514
+ return feature => {
1515
+ const f = feature.properties || feature;
1516
+ const featurePassesFilter = passesFilter(columns, filters, f, filtersLogicalOperator);
1517
+ return type === 'number' ? Number(featurePassesFilter) : featurePassesFilter;
1515
1518
  };
1516
- if (filters) {
1517
- urlParameters.filters = filters;
1519
+ }
1520
+ // Apply certain filters to a collection of features
1521
+ function applyFilters(features, filters, filtersLogicalOperator) {
1522
+ return Object.keys(filters).length ? features.filter(buildFeatureFilter({
1523
+ filters,
1524
+ filtersLogicalOperator
1525
+ })) : features;
1526
+ }
1527
+ // Binary
1528
+ function buildBinaryFeatureFilter({
1529
+ filters = {}
1530
+ }) {
1531
+ const columns = Object.keys(filters);
1532
+ if (!columns.length) {
1533
+ return () => 1;
1518
1534
  }
1519
- return baseSource('raster', options, urlParameters);
1535
+ return (featureIdIdx, binaryData) => passesFilterUsingBinary(columns, filters, featureIdIdx, binaryData);
1536
+ }
1537
+ function getValueFromNumericProps(featureIdIdx, binaryData, {
1538
+ column
1539
+ }) {
1540
+ var _binaryData$numericPr;
1541
+ return (_binaryData$numericPr = binaryData.numericProps) == null || (_binaryData$numericPr = _binaryData$numericPr[column]) == null ? void 0 : _binaryData$numericPr.value[featureIdIdx];
1542
+ }
1543
+ function getValueFromProperties(featureIdIdx, binaryData, {
1544
+ column
1545
+ }) {
1546
+ var _binaryData$propertie;
1547
+ const propertyIdx = binaryData.featureIds.value[featureIdIdx];
1548
+ return (_binaryData$propertie = binaryData.properties[propertyIdx]) == null ? void 0 : _binaryData$propertie[column];
1549
+ }
1550
+ const GET_VALUE_BY_BINARY_PROP = {
1551
+ properties: getValueFromProperties,
1552
+ numericProps: getValueFromNumericProps
1520
1553
  };
1521
-
1522
- const quadbinQuerySource = async function quadbinQuerySource(options) {
1554
+ function getBinaryPropertyByFilterValues(filterValues) {
1555
+ return typeof filterValues.flat()[0] === 'string' ? 'properties' : 'numericProps';
1556
+ }
1557
+ function getFeatureValue(featureIdIdx, binaryData, filter) {
1523
1558
  const {
1524
- aggregationExp,
1525
- aggregationResLevel = DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN,
1526
- sqlQuery,
1527
- spatialDataColumn = 'quadbin',
1528
- queryParameters,
1529
- filters
1530
- } = options;
1531
- const urlParameters = {
1532
- aggregationExp,
1533
- q: sqlQuery,
1534
- spatialDataColumn,
1535
- spatialDataType: 'quadbin'
1536
- };
1537
- if (aggregationResLevel) {
1538
- urlParameters.aggregationResLevel = String(aggregationResLevel);
1559
+ column,
1560
+ values
1561
+ } = filter;
1562
+ const binaryProp = getBinaryPropertyByFilterValues(values);
1563
+ const getFeatureValueFn = GET_VALUE_BY_BINARY_PROP[binaryProp];
1564
+ return getFeatureValueFn(featureIdIdx, binaryData, {
1565
+ column
1566
+ });
1567
+ }
1568
+ function passesFilterUsingBinary(columns, filters, featureIdIdx, binaryData) {
1569
+ return columns.every(column => {
1570
+ const columnFilters = filters[column];
1571
+ return Object.entries(columnFilters).every(([type, {
1572
+ values
1573
+ }]) => {
1574
+ const filterFn = filterFunctions[type];
1575
+ if (!filterFn) {
1576
+ throw new Error(`"${type}" filter is not implemented.`);
1577
+ }
1578
+ if (!values) return 0;
1579
+ const featureValue = getFeatureValue(featureIdIdx, binaryData, {
1580
+ type: type,
1581
+ column,
1582
+ values
1583
+ });
1584
+ if (featureValue === undefined || featureValue === null) return 0;
1585
+ return filterFn(values, featureValue);
1586
+ });
1587
+ });
1588
+ }
1589
+
1590
+ function geojsonFeatures({
1591
+ geojson,
1592
+ spatialFilter,
1593
+ uniqueIdProperty
1594
+ }) {
1595
+ let uniqueIdx = 0;
1596
+ const map = new Map();
1597
+ if (!spatialFilter) {
1598
+ return [];
1539
1599
  }
1540
- if (queryParameters) {
1541
- urlParameters.queryParameters = queryParameters;
1600
+ for (const feature of geojson.features) {
1601
+ const uniqueId = uniqueIdProperty ? feature.properties[uniqueIdProperty] : ++uniqueIdx;
1602
+ if (!map.has(uniqueId) && intersects(spatialFilter, feature)) {
1603
+ map.set(uniqueId, feature.properties);
1604
+ }
1542
1605
  }
1543
- if (filters) {
1544
- urlParameters.filters = filters;
1606
+ return Array.from(map.values());
1607
+ }
1608
+
1609
+ // math.gl
1610
+ // SPDX-License-Identifier: MIT
1611
+ // Copyright (c) vis.gl contributors
1612
+ const DEFAULT_CONFIG = {
1613
+ EPSILON: 1e-12,
1614
+ debug: false,
1615
+ precision: 4,
1616
+ printTypes: false,
1617
+ printDegrees: false,
1618
+ printRowMajor: true,
1619
+ _cartographicRadians: false
1620
+ };
1621
+ // Configuration is truly global as of v3.6 to ensure single config even if multiple copies of math.gl
1622
+ // Multiple copies of config can be quite tricky to debug...
1623
+ globalThis.mathgl = globalThis.mathgl || {
1624
+ config: {
1625
+ ...DEFAULT_CONFIG
1545
1626
  }
1546
- return baseSource('query', options, urlParameters).then(result => _extends({}, result, {
1547
- widgetSource: new WidgetQuerySource(_extends({}, options, {
1548
- // NOTE: passing redundant spatialDataColumn here to apply the default value 'quadbin'
1549
- spatialDataColumn,
1550
- spatialDataType: 'quadbin'
1551
- }))
1552
- }));
1553
1627
  };
1554
-
1555
- const quadbinTableSource = async function quadbinTableSource(options) {
1556
- const {
1557
- aggregationExp,
1558
- aggregationResLevel = DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN,
1559
- spatialDataColumn = 'quadbin',
1560
- tableName,
1561
- filters
1562
- } = options;
1563
- const urlParameters = {
1564
- aggregationExp,
1565
- name: tableName,
1566
- spatialDataColumn,
1567
- spatialDataType: 'quadbin'
1568
- };
1569
- if (aggregationResLevel) {
1570
- urlParameters.aggregationResLevel = String(aggregationResLevel);
1628
+ /**
1629
+ * Check if value is an "array"
1630
+ * Returns `true` if value is either an array or a typed array
1631
+ * Note: returns `false` for `ArrayBuffer` and `DataView` instances
1632
+ * @note isTypedArray and isNumericArray are often more useful in TypeScript
1633
+ */
1634
+ function isArray(value) {
1635
+ return Array.isArray(value) || ArrayBuffer.isView(value) && !(value instanceof DataView);
1636
+ }
1637
+ function lerp(a, b, t) {
1638
+ if (isArray(a)) {
1639
+ return a.map((ai, i) => lerp(ai, b[i], t));
1571
1640
  }
1572
- if (filters) {
1573
- urlParameters.filters = filters;
1641
+ return t * b + (1 - t) * a;
1642
+ }
1643
+
1644
+ // Replacement for the external assert method to reduce bundle size
1645
+ // Note: We don't use the second "message" argument in calling code,
1646
+ // so no need to support it here
1647
+ function assert(condition, message) {
1648
+ if (!condition) {
1649
+ throw new Error(message || '@math.gl/web-mercator: assertion failed.');
1574
1650
  }
1575
- return baseSource('table', options, urlParameters).then(result => _extends({}, result, {
1576
- widgetSource: new WidgetTableSource(_extends({}, options, {
1577
- // NOTE: passing redundant spatialDataColumn here to apply the default value 'quadbin'
1578
- spatialDataColumn,
1579
- spatialDataType: 'quadbin'
1580
- }))
1581
- }));
1582
- };
1651
+ }
1583
1652
 
1584
- // deck.gl
1585
- const quadbinTilesetSource = async function quadbinTilesetSource(options) {
1653
+ // TODO - THE UTILITIES IN THIS FILE SHOULD BE IMPORTED FROM WEB-MERCATOR-VIEWPORT MODULE
1654
+ // CONSTANTS
1655
+ const PI = Math.PI;
1656
+ const PI_4 = PI / 4;
1657
+ const DEGREES_TO_RADIANS = PI / 180;
1658
+ const RADIANS_TO_DEGREES = 180 / PI;
1659
+ const TILE_SIZE = 512;
1660
+ /**
1661
+ * Project [lng,lat] on sphere onto [x,y] on 512*512 Mercator Zoom 0 tile.
1662
+ * Performs the nonlinear part of the web mercator projection.
1663
+ * Remaining projection is done with 4x4 matrices which also handles
1664
+ * perspective.
1665
+ *
1666
+ * @param lngLat - [lng, lat] coordinates
1667
+ * Specifies a point on the sphere to project onto the map.
1668
+ * @return [x,y] coordinates.
1669
+ */
1670
+ function lngLatToWorld(lngLat) {
1671
+ const [lng, lat] = lngLat;
1672
+ assert(Number.isFinite(lng));
1673
+ assert(Number.isFinite(lat) && lat >= -90 && lat <= 90, 'invalid latitude');
1674
+ const lambda2 = lng * DEGREES_TO_RADIANS;
1675
+ const phi2 = lat * DEGREES_TO_RADIANS;
1676
+ const x = TILE_SIZE * (lambda2 + PI) / (2 * PI);
1677
+ const y = TILE_SIZE * (PI + Math.log(Math.tan(PI_4 + phi2 * 0.5))) / (2 * PI);
1678
+ return [x, y];
1679
+ }
1680
+ /**
1681
+ * Unproject world point [x,y] on map onto {lat, lon} on sphere
1682
+ *
1683
+ * @param xy - array with [x,y] members
1684
+ * representing point on projected map plane
1685
+ * @return - array with [x,y] of point on sphere.
1686
+ * Has toArray method if you need a GeoJSON Array.
1687
+ * Per cartographic tradition, lat and lon are specified as degrees.
1688
+ */
1689
+ function worldToLngLat(xy) {
1690
+ const [x, y] = xy;
1691
+ const lambda2 = x / TILE_SIZE * (2 * PI) - PI;
1692
+ const phi2 = 2 * (Math.atan(Math.exp(y / TILE_SIZE * (2 * PI) - PI)) - PI_4);
1693
+ return [lambda2 * RADIANS_TO_DEGREES, phi2 * RADIANS_TO_DEGREES];
1694
+ }
1695
+
1696
+ const TRANSFORM_FN$1 = {
1697
+ Point: transformPoint$1,
1698
+ MultiPoint: transformMultiPoint$1,
1699
+ LineString: transformLineString$1,
1700
+ MultiLineString: transformMultiLineString$1,
1701
+ Polygon: transformPolygon$1,
1702
+ MultiPolygon: transformMultiPolygon$1
1703
+ };
1704
+ /**
1705
+ * Transform WGS84 coordinates to tile coords.
1706
+ * 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)
1707
+ *
1708
+ * @param geometry - any valid geojson geometry
1709
+ * @param bbox - geojson bbox
1710
+ */
1711
+ function transformToTileCoords(geometry, bbox) {
1712
+ const [west, south, east, north] = bbox;
1713
+ const nw = projectFlat([west, north]);
1714
+ const se = projectFlat([east, south]);
1715
+ const projectedBbox = [nw, se];
1716
+ if (geometry.type === 'GeometryCollection') {
1717
+ throw new Error('Unsupported geometry type GeometryCollection');
1718
+ }
1719
+ const transformFn = TRANSFORM_FN$1[geometry.type];
1720
+ const coordinates = transformFn(geometry.coordinates, projectedBbox);
1721
+ return _extends({}, geometry, {
1722
+ coordinates
1723
+ });
1724
+ }
1725
+ function transformPoint$1([pointX, pointY], [nw, se]) {
1726
+ const x = inverseLerp(nw[0], se[0], pointX);
1727
+ const y = inverseLerp(nw[1], se[1], pointY);
1728
+ return [x, y];
1729
+ }
1730
+ function getPoints$1(geometry, bbox) {
1731
+ return geometry.map(g => transformPoint$1(projectFlat(g), bbox));
1732
+ }
1733
+ function transformMultiPoint$1(multiPoint, bbox) {
1734
+ return getPoints$1(multiPoint, bbox);
1735
+ }
1736
+ function transformLineString$1(line, bbox) {
1737
+ return getPoints$1(line, bbox);
1738
+ }
1739
+ function transformMultiLineString$1(multiLineString, bbox) {
1740
+ return multiLineString.map(lineString => transformLineString$1(lineString, bbox));
1741
+ }
1742
+ function transformPolygon$1(polygon, bbox) {
1743
+ return polygon.map(polygonRing => getPoints$1(polygonRing, bbox));
1744
+ }
1745
+ function transformMultiPolygon$1(multiPolygon, bbox) {
1746
+ return multiPolygon.map(polygon => transformPolygon$1(polygon, bbox));
1747
+ }
1748
+ function projectFlat(xyz) {
1749
+ return lngLatToWorld(xyz);
1750
+ }
1751
+ function inverseLerp(a, b, x) {
1752
+ return (x - a) / (b - a);
1753
+ }
1754
+
1755
+ const TRANSFORM_FN = {
1756
+ Point: transformPoint,
1757
+ MultiPoint: transformMultiPoint,
1758
+ LineString: transformLineString,
1759
+ MultiLineString: transformMultiLineString,
1760
+ Polygon: transformPolygon,
1761
+ MultiPolygon: transformMultiPolygon
1762
+ };
1763
+ /**
1764
+ * Transform tile coords to WGS84 coordinates.
1765
+ *
1766
+ * @param geometry - any valid geojson geometry
1767
+ * @param bbox - geojson bbox
1768
+ */
1769
+ function transformTileCoordsToWGS84(geometry, bbox) {
1770
+ const [west, south, east, north] = bbox;
1771
+ const nw = lngLatToWorld([west, north]);
1772
+ const se = lngLatToWorld([east, south]);
1773
+ const projectedBbox = [nw, se];
1774
+ if (geometry.type === 'GeometryCollection') {
1775
+ throw new Error('Unsupported geometry type GeometryCollection');
1776
+ }
1777
+ const transformFn = TRANSFORM_FN[geometry.type];
1778
+ const coordinates = transformFn(geometry.coordinates, projectedBbox);
1779
+ return _extends({}, geometry, {
1780
+ coordinates
1781
+ });
1782
+ }
1783
+ function transformPoint([pointX, pointY], [nw, se]) {
1784
+ const x = lerp(nw[0], se[0], pointX);
1785
+ const y = lerp(nw[1], se[1], pointY);
1786
+ return worldToLngLat([x, y]);
1787
+ }
1788
+ function getPoints(geometry, bbox) {
1789
+ return geometry.map(g => transformPoint(g, bbox));
1790
+ }
1791
+ function transformMultiPoint(multiPoint, bbox) {
1792
+ return getPoints(multiPoint, bbox);
1793
+ }
1794
+ function transformLineString(line, bbox) {
1795
+ return getPoints(line, bbox);
1796
+ }
1797
+ function transformMultiLineString(multiLineString, bbox) {
1798
+ return multiLineString.map(lineString => transformLineString(lineString, bbox));
1799
+ }
1800
+ function transformPolygon(polygon, bbox) {
1801
+ return polygon.map(polygonRing => getPoints(polygonRing, bbox));
1802
+ }
1803
+ function transformMultiPolygon(multiPolygon, bbox) {
1804
+ return multiPolygon.map(polygon => transformPolygon(polygon, bbox));
1805
+ }
1806
+
1807
+ const FEATURE_GEOM_PROPERTY = '__geomValue';
1808
+ function tileFeaturesGeometries({
1809
+ tiles,
1810
+ tileFormat,
1811
+ spatialFilter,
1812
+ uniqueIdProperty,
1813
+ options
1814
+ }) {
1815
+ const map = new Map();
1816
+ for (const tile of tiles) {
1817
+ // Discard if it's not a visible tile (only check false value, not undefined)
1818
+ // or tile has not data
1819
+ if (tile.isVisible === false || !tile.data) {
1820
+ continue;
1821
+ }
1822
+ const bbox = [tile.bbox.west, tile.bbox.south, tile.bbox.east, tile.bbox.north];
1823
+ const bboxToGeom = bboxPolygon(bbox);
1824
+ const tileIsFullyVisible = booleanWithin(bboxToGeom, spatialFilter);
1825
+ // Clip the geometry to intersect with the tile
1826
+ const spatialFilterFeature = {
1827
+ type: 'Feature',
1828
+ geometry: spatialFilter,
1829
+ properties: {}
1830
+ };
1831
+ const clippedGeometryToIntersect = intersect(featureCollection([bboxToGeom, spatialFilterFeature]));
1832
+ if (!clippedGeometryToIntersect) {
1833
+ continue;
1834
+ }
1835
+ // We assume that MVT tileFormat uses local coordinates so we transform the geometry to intersect to tile coordinates [0..1],
1836
+ // while in the case of 'geojson' or binary, the geometries are already in WGS84
1837
+ const transformedGeometryToIntersect = tileFormat === TileFormat.MVT ? transformToTileCoords(clippedGeometryToIntersect.geometry, bbox) : clippedGeometryToIntersect.geometry;
1838
+ createIndicesForPoints(tile.data.points);
1839
+ calculateFeatures({
1840
+ map,
1841
+ tileIsFullyVisible,
1842
+ geometryIntersection: transformedGeometryToIntersect,
1843
+ data: tile.data.points,
1844
+ type: 'Point',
1845
+ bbox,
1846
+ tileFormat,
1847
+ uniqueIdProperty,
1848
+ options
1849
+ });
1850
+ calculateFeatures({
1851
+ map,
1852
+ tileIsFullyVisible,
1853
+ geometryIntersection: transformedGeometryToIntersect,
1854
+ data: tile.data.lines,
1855
+ type: 'LineString',
1856
+ bbox,
1857
+ tileFormat,
1858
+ uniqueIdProperty,
1859
+ options
1860
+ });
1861
+ calculateFeatures({
1862
+ map,
1863
+ tileIsFullyVisible,
1864
+ geometryIntersection: transformedGeometryToIntersect,
1865
+ data: tile.data.polygons,
1866
+ type: 'Polygon',
1867
+ bbox,
1868
+ tileFormat,
1869
+ uniqueIdProperty,
1870
+ options
1871
+ });
1872
+ }
1873
+ return Array.from(map.values());
1874
+ }
1875
+ function processTileFeatureProperties({
1876
+ map,
1877
+ data,
1878
+ startIndex,
1879
+ endIndex,
1880
+ type,
1881
+ bbox,
1882
+ tileFormat,
1883
+ uniqueIdProperty,
1884
+ storeGeometry,
1885
+ geometryIntersection
1886
+ }) {
1887
+ const tileProps = getPropertiesFromTile(data, startIndex);
1888
+ const uniquePropertyValue = getUniquePropertyValue(tileProps, uniqueIdProperty, map);
1889
+ if (!uniquePropertyValue || map.has(uniquePropertyValue)) {
1890
+ return;
1891
+ }
1892
+ let geometry = null;
1893
+ // Only calculate geometry if necessary
1894
+ if (storeGeometry || geometryIntersection) {
1895
+ const {
1896
+ positions
1897
+ } = data;
1898
+ const ringCoordinates = getRingCoordinatesFor(startIndex, endIndex, positions);
1899
+ geometry = getFeatureByType(ringCoordinates, type);
1900
+ }
1901
+ // If intersection is required, check before proceeding
1902
+ if (geometry && geometryIntersection && !intersects(geometry, geometryIntersection)) {
1903
+ return;
1904
+ }
1905
+ const properties = parseProperties(tileProps);
1906
+ // Only save geometry if necessary
1907
+ if (storeGeometry && geometry) {
1908
+ properties[FEATURE_GEOM_PROPERTY] = tileFormat === TileFormat.MVT ? transformTileCoordsToWGS84(geometry, bbox) : geometry;
1909
+ }
1910
+ map.set(uniquePropertyValue, properties);
1911
+ }
1912
+ function addIntersectedFeaturesInTile({
1913
+ map,
1914
+ data,
1915
+ geometryIntersection,
1916
+ type,
1917
+ bbox,
1918
+ tileFormat,
1919
+ uniqueIdProperty,
1920
+ options
1921
+ }) {
1922
+ const indices = getIndices(data);
1923
+ const storeGeometry = (options == null ? void 0 : options.storeGeometry) || false;
1924
+ for (let i = 0; i < indices.length - 1; i++) {
1925
+ const startIndex = indices[i];
1926
+ const endIndex = indices[i + 1];
1927
+ processTileFeatureProperties({
1928
+ map,
1929
+ data,
1930
+ startIndex,
1931
+ endIndex,
1932
+ type,
1933
+ bbox,
1934
+ tileFormat,
1935
+ uniqueIdProperty,
1936
+ storeGeometry,
1937
+ geometryIntersection
1938
+ });
1939
+ }
1940
+ }
1941
+ function getIndices(data) {
1942
+ let indices;
1943
+ switch (data.type) {
1944
+ case 'Point':
1945
+ // @ts-expect-error Missing or changed types?
1946
+ indices = data.pointIndices;
1947
+ break;
1948
+ case 'LineString':
1949
+ indices = data.pathIndices;
1950
+ break;
1951
+ case 'Polygon':
1952
+ indices = data.primitivePolygonIndices;
1953
+ break;
1954
+ default:
1955
+ throw new Error(`Unexpected type, "${data.type}"`);
1956
+ }
1957
+ return indices.value;
1958
+ }
1959
+ function getFeatureId(data, startIndex) {
1960
+ return data.featureIds.value[startIndex];
1961
+ }
1962
+ function getPropertiesFromTile(data, startIndex) {
1963
+ var _fields$featureId;
1964
+ const featureId = getFeatureId(data, startIndex);
1965
+ const {
1966
+ properties,
1967
+ numericProps,
1968
+ fields
1969
+ } = data;
1970
+ const result = {
1971
+ uniqueId: fields == null || (_fields$featureId = fields[featureId]) == null ? void 0 : _fields$featureId.id,
1972
+ properties: properties[featureId],
1973
+ numericProps: {}
1974
+ };
1975
+ for (const key in numericProps) {
1976
+ result.numericProps[key] = numericProps[key].value[startIndex];
1977
+ }
1978
+ return result;
1979
+ }
1980
+ function parseProperties(tileProps) {
1981
+ const {
1982
+ properties,
1983
+ numericProps
1984
+ } = tileProps;
1985
+ return Object.assign({}, properties, numericProps);
1986
+ }
1987
+ function getUniquePropertyValue(tileProps, uniqueIdProperty, map) {
1988
+ if (uniqueIdProperty) {
1989
+ return getValueFromTileProps(tileProps, uniqueIdProperty);
1990
+ }
1991
+ if (tileProps.uniqueId) {
1992
+ return tileProps.uniqueId;
1993
+ }
1994
+ const artificialId = map.size + 1; // a counter, assumed as a valid new id
1995
+ return getValueFromTileProps(tileProps, 'cartodb_id') || getValueFromTileProps(tileProps, 'geoid') || artificialId;
1996
+ }
1997
+ function getValueFromTileProps(tileProps, propertyName) {
1998
+ const {
1999
+ properties,
2000
+ numericProps
2001
+ } = tileProps;
2002
+ return numericProps[propertyName] || properties[propertyName];
2003
+ }
2004
+ function getFeatureByType(coordinates, type) {
2005
+ switch (type) {
2006
+ case 'Polygon':
2007
+ return {
2008
+ type: 'Polygon',
2009
+ coordinates: [coordinates]
2010
+ };
2011
+ case 'LineString':
2012
+ return {
2013
+ type: 'LineString',
2014
+ coordinates
2015
+ };
2016
+ case 'Point':
2017
+ return {
2018
+ type: 'Point',
2019
+ coordinates: coordinates[0]
2020
+ };
2021
+ default:
2022
+ throw new Error('Invalid geometry type');
2023
+ }
2024
+ }
2025
+ function getRingCoordinatesFor(startIndex, endIndex, positions) {
2026
+ const ringCoordinates = [];
2027
+ for (let j = startIndex; j < endIndex; j++) {
2028
+ ringCoordinates.push(Array.from(positions.value.subarray(j * positions.size, (j + 1) * positions.size)));
2029
+ }
2030
+ return ringCoordinates;
2031
+ }
2032
+ function calculateFeatures({
2033
+ map,
2034
+ tileIsFullyVisible,
2035
+ geometryIntersection,
2036
+ data,
2037
+ type,
2038
+ bbox,
2039
+ tileFormat,
2040
+ uniqueIdProperty,
2041
+ options
2042
+ }) {
2043
+ if (!(data != null && data.properties.length)) {
2044
+ return;
2045
+ }
2046
+ if (tileIsFullyVisible) {
2047
+ addAllFeaturesInTile({
2048
+ map,
2049
+ data,
2050
+ type,
2051
+ bbox,
2052
+ tileFormat,
2053
+ uniqueIdProperty,
2054
+ options
2055
+ });
2056
+ } else {
2057
+ addIntersectedFeaturesInTile({
2058
+ map,
2059
+ data,
2060
+ geometryIntersection,
2061
+ type,
2062
+ bbox,
2063
+ tileFormat,
2064
+ uniqueIdProperty,
2065
+ options
2066
+ });
2067
+ }
2068
+ }
2069
+ function addAllFeaturesInTile({
2070
+ map,
2071
+ data,
2072
+ type,
2073
+ bbox,
2074
+ tileFormat,
2075
+ uniqueIdProperty,
2076
+ options
2077
+ }) {
2078
+ const indices = getIndices(data);
2079
+ const storeGeometry = (options == null ? void 0 : options.storeGeometry) || false;
2080
+ for (let i = 0; i < indices.length - 1; i++) {
2081
+ const startIndex = indices[i];
2082
+ const endIndex = indices[i + 1];
2083
+ processTileFeatureProperties({
2084
+ map,
2085
+ data,
2086
+ startIndex,
2087
+ endIndex,
2088
+ type,
2089
+ bbox,
2090
+ tileFormat,
2091
+ uniqueIdProperty,
2092
+ storeGeometry
2093
+ });
2094
+ }
2095
+ }
2096
+ function createIndicesForPoints(data) {
2097
+ const featureIds = data.featureIds.value;
2098
+ const lastFeatureId = featureIds[featureIds.length - 1];
2099
+ const PointIndicesArray = featureIds.constructor;
2100
+ const pointIndices = {
2101
+ value: new PointIndicesArray(featureIds.length + 1),
2102
+ size: 1
2103
+ };
2104
+ pointIndices.value.set(featureIds);
2105
+ pointIndices.value.set([lastFeatureId + 1], featureIds.length);
2106
+ // @ts-expect-error Missing or changed types?
2107
+ data.pointIndices = pointIndices;
2108
+ }
2109
+
2110
+ // a tile is an array [x,y,z]
2111
+ var d2r = Math.PI / 180,
2112
+ r2d = 180 / Math.PI;
2113
+ function tileToBBOX(tile) {
2114
+ var e = tile2lon(tile[0] + 1, tile[2]);
2115
+ var w = tile2lon(tile[0], tile[2]);
2116
+ var s = tile2lat(tile[1] + 1, tile[2]);
2117
+ var n = tile2lat(tile[1], tile[2]);
2118
+ return [w, s, e, n];
2119
+ }
2120
+ function tileToGeoJSON(tile) {
2121
+ var bbox = tileToBBOX(tile);
2122
+ var poly = {
2123
+ type: 'Polygon',
2124
+ coordinates: [[[bbox[0], bbox[1]], [bbox[0], bbox[3]], [bbox[2], bbox[3]], [bbox[2], bbox[1]], [bbox[0], bbox[1]]]]
2125
+ };
2126
+ return poly;
2127
+ }
2128
+ function tile2lon(x, z) {
2129
+ return x / Math.pow(2, z) * 360 - 180;
2130
+ }
2131
+ function tile2lat(y, z) {
2132
+ var n = Math.PI - 2 * Math.PI * y / Math.pow(2, z);
2133
+ return r2d * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)));
2134
+ }
2135
+ function pointToTile(lon, lat, z) {
2136
+ var tile = pointToTileFraction(lon, lat, z);
2137
+ tile[0] = Math.floor(tile[0]);
2138
+ tile[1] = Math.floor(tile[1]);
2139
+ return tile;
2140
+ }
2141
+ function getChildren(tile) {
2142
+ return [[tile[0] * 2, tile[1] * 2, tile[2] + 1], [tile[0] * 2 + 1, tile[1] * 2, tile[2] + 1], [tile[0] * 2 + 1, tile[1] * 2 + 1, tile[2] + 1], [tile[0] * 2, tile[1] * 2 + 1, tile[2] + 1]];
2143
+ }
2144
+ function getParent(tile) {
2145
+ // top left
2146
+ if (tile[0] % 2 === 0 && tile[1] % 2 === 0) {
2147
+ return [tile[0] / 2, tile[1] / 2, tile[2] - 1];
2148
+ }
2149
+ // bottom left
2150
+ else if (tile[0] % 2 === 0 && !tile[1] % 2 === 0) {
2151
+ return [tile[0] / 2, (tile[1] - 1) / 2, tile[2] - 1];
2152
+ }
2153
+ // top right
2154
+ else if (!tile[0] % 2 === 0 && tile[1] % 2 === 0) {
2155
+ return [(tile[0] - 1) / 2, tile[1] / 2, tile[2] - 1];
2156
+ }
2157
+ // bottom right
2158
+ else {
2159
+ return [(tile[0] - 1) / 2, (tile[1] - 1) / 2, tile[2] - 1];
2160
+ }
2161
+ }
2162
+ function getSiblings(tile) {
2163
+ return getChildren(getParent(tile));
2164
+ }
2165
+ function hasSiblings(tile, tiles) {
2166
+ var siblings = getSiblings(tile);
2167
+ for (var i = 0; i < siblings.length; i++) {
2168
+ if (!hasTile(tiles, siblings[i])) return false;
2169
+ }
2170
+ return true;
2171
+ }
2172
+ function hasTile(tiles, tile) {
2173
+ for (var i = 0; i < tiles.length; i++) {
2174
+ if (tilesEqual(tiles[i], tile)) return true;
2175
+ }
2176
+ return false;
2177
+ }
2178
+ function tilesEqual(tile1, tile2) {
2179
+ return tile1[0] === tile2[0] && tile1[1] === tile2[1] && tile1[2] === tile2[2];
2180
+ }
2181
+ function tileToQuadkey(tile) {
2182
+ var index = '';
2183
+ for (var z = tile[2]; z > 0; z--) {
2184
+ var b = 0;
2185
+ var mask = 1 << z - 1;
2186
+ if ((tile[0] & mask) !== 0) b++;
2187
+ if ((tile[1] & mask) !== 0) b += 2;
2188
+ index += b.toString();
2189
+ }
2190
+ return index;
2191
+ }
2192
+ function quadkeyToTile(quadkey) {
2193
+ var x = 0;
2194
+ var y = 0;
2195
+ var z = quadkey.length;
2196
+ for (var i = z; i > 0; i--) {
2197
+ var mask = 1 << i - 1;
2198
+ switch (quadkey[z - i]) {
2199
+ case '0':
2200
+ break;
2201
+ case '1':
2202
+ x |= mask;
2203
+ break;
2204
+ case '2':
2205
+ y |= mask;
2206
+ break;
2207
+ case '3':
2208
+ x |= mask;
2209
+ y |= mask;
2210
+ break;
2211
+ }
2212
+ }
2213
+ return [x, y, z];
2214
+ }
2215
+ function bboxToTile(bboxCoords) {
2216
+ var min = pointToTile(bboxCoords[0], bboxCoords[1], 32);
2217
+ var max = pointToTile(bboxCoords[2], bboxCoords[3], 32);
2218
+ var bbox = [min[0], min[1], max[0], max[1]];
2219
+ var z = getBboxZoom(bbox);
2220
+ if (z === 0) return [0, 0, 0];
2221
+ var x = bbox[0] >>> 32 - z;
2222
+ var y = bbox[1] >>> 32 - z;
2223
+ return [x, y, z];
2224
+ }
2225
+ function getBboxZoom(bbox) {
2226
+ var MAX_ZOOM = 28;
2227
+ for (var z = 0; z < MAX_ZOOM; z++) {
2228
+ var mask = 1 << 32 - (z + 1);
2229
+ if ((bbox[0] & mask) != (bbox[2] & mask) || (bbox[1] & mask) != (bbox[3] & mask)) {
2230
+ return z;
2231
+ }
2232
+ }
2233
+ return MAX_ZOOM;
2234
+ }
2235
+ function pointToTileFraction(lon, lat, z) {
2236
+ var sin = Math.sin(lat * d2r),
2237
+ z2 = Math.pow(2, z),
2238
+ x = z2 * (lon / 360 + 0.5),
2239
+ y = z2 * (0.5 - 0.25 * Math.log((1 + sin) / (1 - sin)) / Math.PI);
2240
+ return [x, y, z];
2241
+ }
2242
+ var tilebelt = {
2243
+ tileToGeoJSON: tileToGeoJSON,
2244
+ tileToBBOX: tileToBBOX,
2245
+ getChildren: getChildren,
2246
+ getParent: getParent,
2247
+ getSiblings: getSiblings,
2248
+ hasTile: hasTile,
2249
+ hasSiblings: hasSiblings,
2250
+ tilesEqual: tilesEqual,
2251
+ tileToQuadkey: tileToQuadkey,
2252
+ quadkeyToTile: quadkeyToTile,
2253
+ pointToTile: pointToTile,
2254
+ bboxToTile: bboxToTile,
2255
+ pointToTileFraction: pointToTileFraction
2256
+ };
2257
+
2258
+ /**
2259
+ * Given a geometry, create cells and return them in their raw form,
2260
+ * as an array of cell identifiers.
2261
+ *
2262
+ * @alias tiles
2263
+ * @param {Object} geom GeoJSON geometry
2264
+ * @param {Object} limits an object with min_zoom and max_zoom properties
2265
+ * specifying the minimum and maximum level to be tiled.
2266
+ * @returns {Array<Array<number>>} An array of tiles given as [x, y, z] arrays
2267
+ */
2268
+ var tiles = getTiles;
2269
+ function getTiles(geom, limits) {
2270
+ var i,
2271
+ tile,
2272
+ coords = geom.coordinates,
2273
+ maxZoom = limits.max_zoom,
2274
+ tileHash = {},
2275
+ tiles = [];
2276
+ if (geom.type === 'Point') {
2277
+ return [tilebelt.pointToTile(coords[0], coords[1], maxZoom)];
2278
+ } else if (geom.type === 'MultiPoint') {
2279
+ for (i = 0; i < coords.length; i++) {
2280
+ tile = tilebelt.pointToTile(coords[i][0], coords[i][1], maxZoom);
2281
+ tileHash[toID(tile[0], tile[1], tile[2])] = true;
2282
+ }
2283
+ } else if (geom.type === 'LineString') {
2284
+ lineCover(tileHash, coords, maxZoom);
2285
+ } else if (geom.type === 'MultiLineString') {
2286
+ for (i = 0; i < coords.length; i++) {
2287
+ lineCover(tileHash, coords[i], maxZoom);
2288
+ }
2289
+ } else if (geom.type === 'Polygon') {
2290
+ polygonCover(tileHash, tiles, coords, maxZoom);
2291
+ } else if (geom.type === 'MultiPolygon') {
2292
+ for (i = 0; i < coords.length; i++) {
2293
+ polygonCover(tileHash, tiles, coords[i], maxZoom);
2294
+ }
2295
+ } else {
2296
+ throw new Error('Geometry type not implemented');
2297
+ }
2298
+ if (limits.min_zoom !== maxZoom) {
2299
+ // sync tile hash and tile array so that both contain the same tiles
2300
+ var len = tiles.length;
2301
+ appendHashTiles(tileHash, tiles);
2302
+ for (i = 0; i < len; i++) {
2303
+ var t = tiles[i];
2304
+ tileHash[toID(t[0], t[1], t[2])] = true;
2305
+ }
2306
+ return mergeTiles(tileHash, tiles, limits);
2307
+ }
2308
+ appendHashTiles(tileHash, tiles);
2309
+ return tiles;
2310
+ }
2311
+ function mergeTiles(tileHash, tiles, limits) {
2312
+ var mergedTiles = [];
2313
+ for (var z = limits.max_zoom; z > limits.min_zoom; z--) {
2314
+ var parentTileHash = {};
2315
+ var parentTiles = [];
2316
+ for (var i = 0; i < tiles.length; i++) {
2317
+ var t = tiles[i];
2318
+ if (t[0] % 2 === 0 && t[1] % 2 === 0) {
2319
+ var id2 = toID(t[0] + 1, t[1], z),
2320
+ id3 = toID(t[0], t[1] + 1, z),
2321
+ id4 = toID(t[0] + 1, t[1] + 1, z);
2322
+ if (tileHash[id2] && tileHash[id3] && tileHash[id4]) {
2323
+ tileHash[toID(t[0], t[1], t[2])] = false;
2324
+ tileHash[id2] = false;
2325
+ tileHash[id3] = false;
2326
+ tileHash[id4] = false;
2327
+ var parentTile = [t[0] / 2, t[1] / 2, z - 1];
2328
+ if (z - 1 === limits.min_zoom) mergedTiles.push(parentTile);else {
2329
+ parentTileHash[toID(t[0] / 2, t[1] / 2, z - 1)] = true;
2330
+ parentTiles.push(parentTile);
2331
+ }
2332
+ }
2333
+ }
2334
+ }
2335
+ for (i = 0; i < tiles.length; i++) {
2336
+ t = tiles[i];
2337
+ if (tileHash[toID(t[0], t[1], t[2])]) mergedTiles.push(t);
2338
+ }
2339
+ tileHash = parentTileHash;
2340
+ tiles = parentTiles;
2341
+ }
2342
+ return mergedTiles;
2343
+ }
2344
+ function polygonCover(tileHash, tileArray, geom, zoom) {
2345
+ var intersections = [];
2346
+ for (var i = 0; i < geom.length; i++) {
2347
+ var ring = [];
2348
+ lineCover(tileHash, geom[i], zoom, ring);
2349
+ for (var j = 0, len = ring.length, k = len - 1; j < len; k = j++) {
2350
+ var m = (j + 1) % len;
2351
+ var y = ring[j][1];
2352
+
2353
+ // add interesction if it's not local extremum or duplicate
2354
+ if ((y > ring[k][1] || y > ring[m][1]) && (
2355
+ // not local minimum
2356
+ y < ring[k][1] || y < ring[m][1]) &&
2357
+ // not local maximum
2358
+ y !== ring[m][1]) intersections.push(ring[j]);
2359
+ }
2360
+ }
2361
+ intersections.sort(compareTiles); // sort by y, then x
2362
+
2363
+ for (i = 0; i < intersections.length; i += 2) {
2364
+ // fill tiles between pairs of intersections
2365
+ y = intersections[i][1];
2366
+ for (var x = intersections[i][0] + 1; x < intersections[i + 1][0]; x++) {
2367
+ var id = toID(x, y, zoom);
2368
+ if (!tileHash[id]) {
2369
+ tileArray.push([x, y, zoom]);
2370
+ }
2371
+ }
2372
+ }
2373
+ }
2374
+ function compareTiles(a, b) {
2375
+ return a[1] - b[1] || a[0] - b[0];
2376
+ }
2377
+ function lineCover(tileHash, coords, maxZoom, ring) {
2378
+ var prevX, prevY;
2379
+ for (var i = 0; i < coords.length - 1; i++) {
2380
+ var start = tilebelt.pointToTileFraction(coords[i][0], coords[i][1], maxZoom),
2381
+ stop = tilebelt.pointToTileFraction(coords[i + 1][0], coords[i + 1][1], maxZoom),
2382
+ x0 = start[0],
2383
+ y0 = start[1],
2384
+ x1 = stop[0],
2385
+ y1 = stop[1],
2386
+ dx = x1 - x0,
2387
+ dy = y1 - y0;
2388
+ if (dy === 0 && dx === 0) continue;
2389
+ var sx = dx > 0 ? 1 : -1,
2390
+ sy = dy > 0 ? 1 : -1,
2391
+ x = Math.floor(x0),
2392
+ y = Math.floor(y0),
2393
+ tMaxX = dx === 0 ? Infinity : Math.abs(((dx > 0 ? 1 : 0) + x - x0) / dx),
2394
+ tMaxY = dy === 0 ? Infinity : Math.abs(((dy > 0 ? 1 : 0) + y - y0) / dy),
2395
+ tdx = Math.abs(sx / dx),
2396
+ tdy = Math.abs(sy / dy);
2397
+ if (x !== prevX || y !== prevY) {
2398
+ tileHash[toID(x, y, maxZoom)] = true;
2399
+ if (ring && y !== prevY) ring.push([x, y]);
2400
+ prevX = x;
2401
+ prevY = y;
2402
+ }
2403
+ while (tMaxX < 1 || tMaxY < 1) {
2404
+ if (tMaxX < tMaxY) {
2405
+ tMaxX += tdx;
2406
+ x += sx;
2407
+ } else {
2408
+ tMaxY += tdy;
2409
+ y += sy;
2410
+ }
2411
+ tileHash[toID(x, y, maxZoom)] = true;
2412
+ if (ring && y !== prevY) ring.push([x, y]);
2413
+ prevX = x;
2414
+ prevY = y;
2415
+ }
2416
+ }
2417
+ if (ring && y === ring[0][1]) ring.pop();
2418
+ }
2419
+ function appendHashTiles(hash, tiles) {
2420
+ var keys = Object.keys(hash);
2421
+ for (var i = 0; i < keys.length; i++) {
2422
+ tiles.push(fromID(+keys[i]));
2423
+ }
2424
+ }
2425
+ function toID(x, y, z) {
2426
+ var dim = 2 * (1 << z);
2427
+ return (dim * y + x) * 32 + z;
2428
+ }
2429
+ function fromID(id) {
2430
+ var z = id % 32,
2431
+ dim = 2 * (1 << z),
2432
+ xy = (id - z) / 32,
2433
+ x = xy % dim,
2434
+ y = (xy - x) / dim % dim;
2435
+ return [x, y, z];
2436
+ }
2437
+
2438
+ const B = [0x5555555555555555n, 0x3333333333333333n, 0x0f0f0f0f0f0f0f0fn, 0x00ff00ff00ff00ffn, 0x0000ffff0000ffffn, 0x00000000ffffffffn];
2439
+ const S = [0n, 1n, 2n, 4n, 8n, 16n];
2440
+ function tileToCell(tile) {
2441
+ if (tile.z < 0 || tile.z > 26) {
2442
+ throw new Error('Wrong zoom');
2443
+ }
2444
+ const z = BigInt(tile.z);
2445
+ let x = BigInt(tile.x) << 32n - z;
2446
+ let y = BigInt(tile.y) << 32n - z;
2447
+ for (let i = 0; i < 5; i++) {
2448
+ const s = S[5 - i];
2449
+ const b = B[4 - i];
2450
+ x = (x | x << s) & b;
2451
+ y = (y | y << s) & b;
2452
+ }
2453
+ const quadbin = 0x4000000000000000n | 1n << 59n |
2454
+ // | (mode << 59) | (mode_dep << 57)
2455
+ z << 52n | (x | y << 1n) >> 12n | 0xfffffffffffffn >> z * 2n;
2456
+ return quadbin;
2457
+ }
2458
+ function getResolution$1(quadbin) {
2459
+ return quadbin >> 52n & 0x1fn;
2460
+ }
2461
+ function geometryToCells(geometry, resolution) {
2462
+ const zoom = Number(resolution);
2463
+ return tiles(geometry, {
2464
+ min_zoom: zoom,
2465
+ max_zoom: zoom
2466
+ }).map(([x, y, z]) => tileToCell({
2467
+ x,
2468
+ y,
2469
+ z
2470
+ }));
2471
+ }
2472
+
2473
+ function tileFeaturesSpatialIndex({
2474
+ tiles,
2475
+ spatialFilter,
2476
+ spatialDataColumn,
2477
+ spatialDataType
2478
+ }) {
2479
+ const map = new Map();
2480
+ const spatialIndex = getSpatialIndex(spatialDataType);
2481
+ const resolution = getResolution(tiles, spatialIndex);
2482
+ const spatialIndexIDName = spatialDataColumn ? spatialDataColumn : spatialIndex;
2483
+ if (!resolution) {
2484
+ return [];
2485
+ }
2486
+ const cells = getCellsCoverGeometry(spatialFilter, spatialIndex, resolution);
2487
+ if (!(cells != null && cells.length)) {
2488
+ return [];
2489
+ }
2490
+ // We transform cells to Set to improve the performace
2491
+ const cellsSet = new Set(cells);
2492
+ for (const tile of tiles) {
2493
+ if (tile.isVisible === false || !tile.data) {
2494
+ continue;
2495
+ }
2496
+ tile.data.forEach(d => {
2497
+ if (cellsSet.has(d.id)) {
2498
+ map.set(d.id, _extends({}, d.properties, {
2499
+ [spatialIndexIDName]: d.id
2500
+ }));
2501
+ }
2502
+ });
2503
+ }
2504
+ return Array.from(map.values());
2505
+ }
2506
+ function getResolution(tiles, spatialIndex) {
2507
+ var _tiles$find;
2508
+ const data = (_tiles$find = tiles.find(tile => {
2509
+ var _tile$data;
2510
+ return (_tile$data = tile.data) == null ? void 0 : _tile$data.length;
2511
+ })) == null ? void 0 : _tiles$find.data;
2512
+ if (!data) {
2513
+ return;
2514
+ }
2515
+ if (spatialIndex === SpatialIndex.QUADBIN) {
2516
+ return Number(getResolution$1(data[0].id));
2517
+ }
2518
+ if (spatialIndex === SpatialIndex.H3) {
2519
+ return getResolution$2(data[0].id);
2520
+ }
2521
+ }
2522
+ const bboxWest = [-180, -90, 0, 90];
2523
+ const bboxEast = [0, -90, 180, 90];
2524
+ function getCellsCoverGeometry(geometry, spatialIndex, resolution) {
2525
+ if (spatialIndex === SpatialIndex.QUADBIN) {
2526
+ // @ts-expect-error TODO: Probably ought to be stricter about number vs. bigint types in this file.
2527
+ return geometryToCells(geometry, resolution);
2528
+ }
2529
+ if (spatialIndex === SpatialIndex.H3) {
2530
+ // The current H3 polyfill algorithm can't deal with polygon segments of greater than 180 degrees longitude
2531
+ // so we clip the geometry to be sure that none of them is greater than 180 degrees
2532
+ // https://github.com/uber/h3-js/issues/24#issuecomment-431893796
2533
+ return polygonToCells(bboxClip(geometry, bboxWest).geometry.coordinates, resolution, true).concat(polygonToCells(bboxClip(geometry, bboxEast).geometry.coordinates, resolution, true));
2534
+ }
2535
+ }
2536
+ function getSpatialIndex(spatialDataType) {
2537
+ switch (spatialDataType) {
2538
+ case 'h3':
2539
+ return SpatialIndex.H3;
2540
+ case 'quadbin':
2541
+ return SpatialIndex.QUADBIN;
2542
+ default:
2543
+ throw new Error('Unexpected spatial data type');
2544
+ }
2545
+ }
2546
+
2547
+ /** @internalRemarks Source: @carto/react-core */
2548
+ function tileFeatures({
2549
+ tiles,
2550
+ spatialFilter,
2551
+ uniqueIdProperty,
2552
+ tileFormat,
2553
+ spatialDataColumn = DEFAULT_GEO_COLUMN,
2554
+ spatialDataType,
2555
+ options = {}
2556
+ }) {
2557
+ // TODO(cleanup): Is an empty response the expected result when spatialFilter
2558
+ // is omitted? Why not make the parameter required, or return the full input?
2559
+ if (!spatialFilter) {
2560
+ return [];
2561
+ }
2562
+ if (spatialDataType !== 'geo') {
2563
+ return tileFeaturesSpatialIndex({
2564
+ tiles: tiles,
2565
+ spatialFilter,
2566
+ spatialDataColumn,
2567
+ spatialDataType
2568
+ });
2569
+ }
2570
+ return tileFeaturesGeometries({
2571
+ tiles,
2572
+ tileFormat,
2573
+ spatialFilter,
2574
+ uniqueIdProperty,
2575
+ options
2576
+ });
2577
+ }
2578
+
2579
+ /** @internalRemarks Source: @carto/react-core */
2580
+ const aggregationFunctions = {
2581
+ count: values => values.length,
2582
+ min: (...args) => applyAggregationFunction(min, ...args),
2583
+ max: (...args) => applyAggregationFunction(max, ...args),
2584
+ sum: (...args) => applyAggregationFunction(sum, ...args),
2585
+ avg: (...args) => applyAggregationFunction(avg, ...args)
2586
+ };
2587
+ /** @internalRemarks Source: @carto/react-core */
2588
+ function aggregate(feature, keys, operation) {
2589
+ if (!(keys != null && keys.length)) {
2590
+ throw new Error('Cannot aggregate a feature without having keys');
2591
+ } else if (keys.length === 1) {
2592
+ const value = feature[keys[0]];
2593
+ return isPotentiallyValidNumber(value) ? Number(value) : value;
2594
+ }
2595
+ const aggregationFn = aggregationFunctions[operation];
2596
+ if (!aggregationFn) {
2597
+ throw new Error(`${operation} isn't a valid aggregation function`);
2598
+ }
2599
+ return aggregationFn(keys.map(column => {
2600
+ const value = feature[column];
2601
+ return isPotentiallyValidNumber(value) ? Number(value) : value;
2602
+ }));
2603
+ }
2604
+ /*
2605
+ * Forced casting to Number (just of non empty strings) allows to work-around
2606
+ * some specific situations, where a big numeric field is transformed into a string when generating the tileset(eg.PG)
2607
+ */
2608
+ function isPotentiallyValidNumber(value) {
2609
+ return typeof value === 'string' && value.trim().length > 0;
2610
+ }
2611
+ const applyAggregationFunction = (aggFn, values, keys, operation) => {
2612
+ const normalizedKeys = normalizeKeys(keys);
2613
+ const elements = ((normalizedKeys == null ? void 0 : normalizedKeys.length) || 0) <= 1 ? filterFalsyElements(values, normalizedKeys || []) : values;
2614
+ return aggFn(elements, keys, operation);
2615
+ };
2616
+ function filterFalsyElements(values, keys) {
2617
+ const filterFn = value => value !== null && value !== undefined;
2618
+ if (!(keys != null && keys.length)) {
2619
+ return values.filter(filterFn);
2620
+ }
2621
+ return values.filter(v => filterFn(v[keys[0]]));
2622
+ }
2623
+ // Aggregation functions
2624
+ function avg(values, keys, joinOperation) {
2625
+ return sum(values, keys, joinOperation) / (values.length || 1);
2626
+ }
2627
+ function sum(values, keys, joinOperation) {
2628
+ const normalizedKeys = normalizeKeys(keys);
2629
+ if (normalizedKeys) {
2630
+ return values.reduce((a, b) => a + aggregate(b, normalizedKeys, joinOperation), 0);
2631
+ }
2632
+ return values.reduce((a, b) => a + b, 0);
2633
+ }
2634
+ function min(values, keys, joinOperation) {
2635
+ const normalizedKeys = normalizeKeys(keys);
2636
+ if (normalizedKeys) {
2637
+ return values.reduce((a, b) => Math.min(a, aggregate(b, normalizedKeys, joinOperation)), Infinity);
2638
+ }
2639
+ return Math.min(...values);
2640
+ }
2641
+ function max(values, keys, joinOperation) {
2642
+ const normalizedKeys = normalizeKeys(keys);
2643
+ if (normalizedKeys) {
2644
+ return values.reduce((a, b) => Math.max(a, aggregate(b, normalizedKeys, joinOperation)), -Infinity);
2645
+ }
2646
+ return Math.max(...values);
2647
+ }
2648
+ // Aux
2649
+ // Keys can come as a string (one column) or a strings array (multiple column)
2650
+ // Use always an array to make the code easier
2651
+ function normalizeKeys(keys) {
2652
+ return Array.isArray(keys) ? keys : typeof keys === 'string' ? [keys] : undefined;
2653
+ }
2654
+
2655
+ /***
2656
+ Copyright 2013 Teun Duynstee
2657
+
2658
+ Licensed under the Apache License, Version 2.0 (the "License");
2659
+ you may not use this file except in compliance with the License.
2660
+ You may obtain a copy of the License at
2661
+
2662
+ http://www.apache.org/licenses/LICENSE-2.0
2663
+
2664
+ Unless required by applicable law or agreed to in writing, software
2665
+ distributed under the License is distributed on an "AS IS" BASIS,
2666
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2667
+ See the License for the specific language governing permissions and
2668
+ limitations under the License.
2669
+ */
2670
+ var thenBy_module = function () {
2671
+ function identity(v) {
2672
+ return v;
2673
+ }
2674
+ function ignoreCase(v) {
2675
+ return typeof v === "string" ? v.toLowerCase() : v;
2676
+ }
2677
+ function makeCompareFunction(f, opt) {
2678
+ opt = typeof opt === "object" ? opt : {
2679
+ direction: opt
2680
+ };
2681
+ if (typeof f != "function") {
2682
+ var prop = f;
2683
+ // make unary function
2684
+ f = function (v1) {
2685
+ return !!v1[prop] ? v1[prop] : "";
2686
+ };
2687
+ }
2688
+ if (f.length === 1) {
2689
+ // f is a unary function mapping a single item to its sort score
2690
+ var uf = f;
2691
+ var preprocess = opt.ignoreCase ? ignoreCase : identity;
2692
+ var cmp = opt.cmp || function (v1, v2) {
2693
+ return v1 < v2 ? -1 : v1 > v2 ? 1 : 0;
2694
+ };
2695
+ f = function (v1, v2) {
2696
+ return cmp(preprocess(uf(v1)), preprocess(uf(v2)));
2697
+ };
2698
+ }
2699
+ const descTokens = {
2700
+ "-1": '',
2701
+ desc: ''
2702
+ };
2703
+ if (opt.direction in descTokens) return function (v1, v2) {
2704
+ return -f(v1, v2);
2705
+ };
2706
+ return f;
2707
+ }
2708
+
2709
+ /* adds a secondary compare function to the target function (`this` context)
2710
+ which is applied in case the first one returns 0 (equal)
2711
+ returns a new compare function, which has a `thenBy` method as well */
2712
+ function tb(func, opt) {
2713
+ /* should get value false for the first call. This can be done by calling the
2714
+ exported function, or the firstBy property on it (for es6 module compatibility)
2715
+ */
2716
+ var x = typeof this == "function" && !this.firstBy ? this : false;
2717
+ var y = makeCompareFunction(func, opt);
2718
+ var f = x ? function (a, b) {
2719
+ return x(a, b) || y(a, b);
2720
+ } : y;
2721
+ f.thenBy = tb;
2722
+ return f;
2723
+ }
2724
+ tb.firstBy = tb;
2725
+ return tb;
2726
+ }();
2727
+
2728
+ /**
2729
+ * Apply sort structure to a collection of features
2730
+ * @param features
2731
+ * @param [sortOptions]
2732
+ * @param [sortOptions.sortBy] - One or more columns to sort by
2733
+ * @param [sortOptions.sortByDirection] - Direction by the columns will be sorted
2734
+ * @param [sortOptions.sortByColumnType] - Column type
2735
+ * @internal
2736
+ * @internalRemarks Source: @carto/react-core
2737
+ */
2738
+ function applySorting(features, {
2739
+ sortBy,
2740
+ sortByDirection = 'asc',
2741
+ sortByColumnType = 'string'
2742
+ } = {}) {
2743
+ // If sortBy is undefined, pass all features
2744
+ if (sortBy === undefined) {
2745
+ return features;
2746
+ }
2747
+ // sortOptions exists, but are bad formatted
2748
+ const isValidSortBy = Array.isArray(sortBy) && sortBy.length ||
2749
+ // sortBy can be an array of columns
2750
+ typeof sortBy === 'string'; // or just one column
2751
+ if (!isValidSortBy) {
2752
+ throw new Error('Sorting options are bad formatted');
2753
+ }
2754
+ const sortFn = createSortFn({
2755
+ sortBy,
2756
+ sortByDirection,
2757
+ sortByColumnType: sortByColumnType || 'string'
2758
+ });
2759
+ return features.sort(sortFn);
2760
+ }
2761
+ // Aux
2762
+ function createSortFn({
2763
+ sortBy,
2764
+ sortByDirection,
2765
+ sortByColumnType
2766
+ }) {
2767
+ const [firstSortOption, ...othersSortOptions] = normalizeSortByOptions({
2768
+ sortBy,
2769
+ sortByDirection,
2770
+ sortByColumnType
2771
+ });
2772
+ let sortFn = thenBy_module.firstBy(...firstSortOption);
2773
+ for (let sortOptions of othersSortOptions) {
2774
+ sortFn = sortFn.thenBy(...sortOptions);
2775
+ }
2776
+ return sortFn;
2777
+ }
2778
+ function normalizeSortByOptions({
2779
+ sortBy,
2780
+ sortByDirection,
2781
+ sortByColumnType
2782
+ }) {
2783
+ const numberFormat = sortByColumnType === 'number' && {
2784
+ cmp: (a, b) => a - b
2785
+ };
2786
+ if (!Array.isArray(sortBy)) {
2787
+ sortBy = [sortBy];
2788
+ }
2789
+ return sortBy.map(sortByEl => {
2790
+ // sortByEl is 'column'
2791
+ if (typeof sortByEl === 'string') {
2792
+ return [sortByEl, _extends({
2793
+ direction: sortByDirection
2794
+ }, numberFormat)];
2795
+ }
2796
+ if (Array.isArray(sortByEl)) {
2797
+ // sortBy is ['column']
2798
+ if (sortByEl[1] === undefined) {
2799
+ return [sortByEl, _extends({
2800
+ direction: sortByDirection
2801
+ }, numberFormat)];
2802
+ }
2803
+ // sortBy is ['column', { ... }]
2804
+ if (typeof sortByEl[1] === 'object') {
2805
+ const othersSortOptions = numberFormat ? _extends({}, numberFormat, sortByEl[1]) : sortByEl[1];
2806
+ return [sortByEl[0], _extends({
2807
+ direction: sortByDirection
2808
+ }, othersSortOptions)];
2809
+ }
2810
+ }
2811
+ return sortByEl;
2812
+ });
2813
+ }
2814
+
2815
+ /** @internalRemarks Source: @carto/react-core */
2816
+ function groupValuesByColumn({
2817
+ data,
2818
+ valuesColumns,
2819
+ joinOperation,
2820
+ keysColumn,
2821
+ operation
2822
+ }) {
2823
+ if (Array.isArray(data) && data.length === 0) {
2824
+ return null;
2825
+ }
2826
+ const groups = data.reduce((accumulator, item) => {
2827
+ const group = item[keysColumn];
2828
+ const values = accumulator.get(group) || [];
2829
+ accumulator.set(group, values);
2830
+ const aggregatedValue = aggregate(item, valuesColumns, joinOperation);
2831
+ const isValid = (operation === 'count' ? true : aggregatedValue !== null) && aggregatedValue !== undefined;
2832
+ if (isValid) {
2833
+ values.push(aggregatedValue);
2834
+ accumulator.set(group, values);
2835
+ }
2836
+ return accumulator;
2837
+ }, new Map()); // We use a map to be able to maintain the type in the key value
2838
+ const targetOperation = aggregationFunctions[operation];
2839
+ if (targetOperation) {
2840
+ return Array.from(groups).map(([name, value]) => ({
2841
+ name,
2842
+ value: targetOperation(value)
2843
+ }));
2844
+ }
2845
+ return [];
2846
+ }
2847
+
2848
+ /**
2849
+ * Returns midnight (local time) on the Monday preceeding a given date, in
2850
+ * milliseconds since the UNIX epoch.
2851
+ */
2852
+ /**
2853
+ * Returns midnight (UTC) on the Monday preceeding a given date, in
2854
+ * milliseconds since the UNIX epoch.
2855
+ */
2856
+ function getUTCMonday(date) {
2857
+ const dateCp = new Date(date);
2858
+ const day = dateCp.getUTCDay();
2859
+ const diff = dateCp.getUTCDate() - day + (day ? 1 : -6); // adjust when day is sunday
2860
+ dateCp.setUTCDate(diff);
2861
+ return Date.UTC(dateCp.getUTCFullYear(), dateCp.getUTCMonth(), dateCp.getUTCDate());
2862
+ }
2863
+
2864
+ const GROUP_KEY_FN_MAPPING = {
2865
+ year: date => Date.UTC(date.getUTCFullYear()),
2866
+ month: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth()),
2867
+ week: date => getUTCMonday(date),
2868
+ day: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()),
2869
+ hour: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours()),
2870
+ minute: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes()),
2871
+ second: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds())
2872
+ };
2873
+ /** @internalRemarks Source: @carto/react-core */
2874
+ function groupValuesByDateColumn({
2875
+ data,
2876
+ valuesColumns,
2877
+ joinOperation,
2878
+ keysColumn,
2879
+ groupType,
2880
+ operation
2881
+ }) {
2882
+ if (Array.isArray(data) && data.length === 0) {
2883
+ return null;
2884
+ }
2885
+ const groupKeyFn = GROUP_KEY_FN_MAPPING[groupType];
2886
+ if (!groupKeyFn) {
2887
+ return null;
2888
+ }
2889
+ const groups = data.reduce((acc, item) => {
2890
+ const value = item[keysColumn];
2891
+ const formattedValue = new Date(value);
2892
+ const groupKey = groupKeyFn(formattedValue);
2893
+ if (!isNaN(groupKey)) {
2894
+ let groupedValues = acc.get(groupKey);
2895
+ if (!groupedValues) {
2896
+ groupedValues = [];
2897
+ acc.set(groupKey, groupedValues);
2898
+ }
2899
+ const aggregatedValue = aggregate(item, valuesColumns, joinOperation);
2900
+ const isValid = aggregatedValue !== null && aggregatedValue !== undefined;
2901
+ if (isValid) {
2902
+ groupedValues.push(aggregatedValue);
2903
+ acc.set(groupKey, groupedValues);
2904
+ }
2905
+ }
2906
+ return acc;
2907
+ }, new Map());
2908
+ const targetOperation = aggregationFunctions[operation];
2909
+ return [...groups.entries()].map(([name, value]) => ({
2910
+ name,
2911
+ value: targetOperation(value)
2912
+ })).sort((a, b) => a.name - b.name);
2913
+ }
2914
+
2915
+ /**
2916
+ * Histogram computation.
2917
+ * @internalRemarks Source: @carto/react-core
2918
+ */
2919
+ function histogram({
2920
+ data,
2921
+ valuesColumns,
2922
+ joinOperation,
2923
+ ticks,
2924
+ operation
2925
+ }) {
2926
+ if (Array.isArray(data) && data.length === 0) {
2927
+ return [];
2928
+ }
2929
+ const binsContainer = [Number.MIN_SAFE_INTEGER, ...ticks].map((tick, index, arr) => ({
2930
+ bin: index,
2931
+ start: tick,
2932
+ end: index === arr.length - 1 ? Number.MAX_SAFE_INTEGER : arr[index + 1],
2933
+ values: []
2934
+ }));
2935
+ data.forEach(feature => {
2936
+ const featureValue = aggregate(feature, valuesColumns, joinOperation);
2937
+ const isValid = featureValue !== null && featureValue !== undefined;
2938
+ if (!isValid) {
2939
+ return;
2940
+ }
2941
+ const binContainer = binsContainer.find(bin => bin.start <= featureValue && bin.end > featureValue);
2942
+ if (!binContainer) {
2943
+ return;
2944
+ }
2945
+ binContainer.values.push(featureValue);
2946
+ });
2947
+ const targetOperation = aggregationFunctions[operation];
2948
+ const transformedBins = binsContainer.map(binContainer => binContainer.values);
2949
+ return transformedBins.map(values => values.length ? targetOperation(values) : 0);
2950
+ }
2951
+
2952
+ /**
2953
+ * Filters invalid features and formats data.
2954
+ * @internalRemarks Source: @carto/react-core
2955
+ */
2956
+ function scatterPlot({
2957
+ data,
2958
+ xAxisColumns,
2959
+ xAxisJoinOperation,
2960
+ yAxisColumns,
2961
+ yAxisJoinOperation
2962
+ }) {
2963
+ return data.reduce((acc, feature) => {
2964
+ const xValue = aggregate(feature, xAxisColumns, xAxisJoinOperation);
2965
+ const xIsValid = xValue !== null && xValue !== undefined;
2966
+ const yValue = aggregate(feature, yAxisColumns, yAxisJoinOperation);
2967
+ const yIsValid = yValue !== null && yValue !== undefined;
2968
+ if (xIsValid && yIsValid) {
2969
+ acc.push([xValue, yValue]);
2970
+ }
2971
+ return acc;
2972
+ }, []);
2973
+ }
2974
+
2975
+ const _excluded = ["filterOwner", "spatialFilter", "abortController"];
2976
+ /**
2977
+ * Source for Widget API requests on a data source defined by a tileset.
2978
+ *
2979
+ * Generally not intended to be constructed directly. Instead, call
2980
+ * {@link vectorTilesetSource}, {@link h3TilesetSource}, or {@link quadbinTilesetSource},
2981
+ * which can be shared with map layers. Sources contain a `widgetSource`
2982
+ * property, for use by widget implementations.
2983
+ *
2984
+ * Example:
2985
+ *
2986
+ * ```javascript
2987
+ * import { vectorTilesetSource } from '@carto/api-client';
2988
+ *
2989
+ * const data = vectorTilesetSource({
2990
+ * accessToken: '••••',
2991
+ * connectionName: 'carto_dw',
2992
+ * tableName: 'carto-demo-data.demo_rasters.my_tileset_source'
2993
+ * });
2994
+ *
2995
+ * const { widgetSource } = await data;
2996
+ * ```
2997
+ */
2998
+ class WidgetTilesetSource extends WidgetSource {
2999
+ constructor(...args) {
3000
+ super(...args);
3001
+ this._features = [];
3002
+ }
3003
+ getModelSource(owner) {
3004
+ return _extends({}, super._getModelSource(owner), {
3005
+ type: 'tileset',
3006
+ data: this.props.tableName
3007
+ });
3008
+ }
3009
+ /** Loads features as a list of tiles (typically provided by deck.gl). */
3010
+ loadTiles({
3011
+ tiles,
3012
+ spatialFilter,
3013
+ uniqueIdProperty,
3014
+ options
3015
+ }) {
3016
+ this._features = tileFeatures({
3017
+ tiles,
3018
+ options,
3019
+ spatialFilter,
3020
+ uniqueIdProperty,
3021
+ tileFormat: this.props.tileFormat,
3022
+ spatialDataColumn: this.props.spatialDataColumn,
3023
+ spatialDataType: this.props.spatialDataType
3024
+ });
3025
+ }
3026
+ /** Loads features as GeoJSON (used for testing). */
3027
+ loadGeoJSON({
3028
+ geojson,
3029
+ spatialFilter,
3030
+ uniqueIdProperty
3031
+ }) {
3032
+ this._features = geojsonFeatures({
3033
+ geojson,
3034
+ spatialFilter,
3035
+ uniqueIdProperty
3036
+ });
3037
+ }
3038
+ async getFeatures(options) {
3039
+ throw new Error('getFeatures not supported for tilesets');
3040
+ }
3041
+ async getFormula({
3042
+ column = '*',
3043
+ operation = 'count',
3044
+ joinOperation,
3045
+ filterOwner
3046
+ }) {
3047
+ if (operation === 'custom') {
3048
+ throw new Error('Custom aggregation not supported for tilesets');
3049
+ }
3050
+ if (!this._features.length) {
3051
+ return {
3052
+ value: null
3053
+ };
3054
+ }
3055
+ // Column is required except when operation is 'count'.
3056
+ if (column && column !== '*' || operation !== 'count') {
3057
+ assertColumn(this._features, column);
3058
+ }
3059
+ const filteredFeatures = this._getFilteredFeatures(filterOwner);
3060
+ if (filteredFeatures.length === 0 && operation !== 'count') {
3061
+ return {
3062
+ value: null
3063
+ };
3064
+ }
3065
+ const targetOperation = aggregationFunctions[operation];
3066
+ return {
3067
+ value: targetOperation(filteredFeatures, column, joinOperation)
3068
+ };
3069
+ }
3070
+ async getHistogram({
3071
+ operation = 'count',
3072
+ ticks,
3073
+ column,
3074
+ joinOperation,
3075
+ filterOwner
3076
+ }) {
3077
+ if (!this._features.length) {
3078
+ return [];
3079
+ }
3080
+ const filteredFeatures = this._getFilteredFeatures(filterOwner);
3081
+ assertColumn(this._features, column);
3082
+ return histogram({
3083
+ data: filteredFeatures,
3084
+ valuesColumns: normalizeColumns(column),
3085
+ joinOperation,
3086
+ ticks,
3087
+ operation
3088
+ });
3089
+ }
3090
+ async getCategories({
3091
+ column,
3092
+ operation = 'count',
3093
+ operationColumn,
3094
+ joinOperation,
3095
+ filterOwner
3096
+ }) {
3097
+ if (!this._features.length) {
3098
+ return [];
3099
+ }
3100
+ const filteredFeatures = this._getFilteredFeatures(filterOwner);
3101
+ assertColumn(this._features, column, operationColumn);
3102
+ const groups = groupValuesByColumn({
3103
+ data: filteredFeatures,
3104
+ valuesColumns: normalizeColumns(operationColumn || column),
3105
+ joinOperation,
3106
+ keysColumn: column,
3107
+ operation
3108
+ });
3109
+ return groups || [];
3110
+ }
3111
+ async getScatter({
3112
+ xAxisColumn,
3113
+ yAxisColumn,
3114
+ xAxisJoinOperation,
3115
+ yAxisJoinOperation,
3116
+ filterOwner
3117
+ }) {
3118
+ if (!this._features.length) {
3119
+ return [];
3120
+ }
3121
+ const filteredFeatures = this._getFilteredFeatures(filterOwner);
3122
+ assertColumn(this._features, xAxisColumn, yAxisColumn);
3123
+ return scatterPlot({
3124
+ data: filteredFeatures,
3125
+ xAxisColumns: normalizeColumns(xAxisColumn),
3126
+ xAxisJoinOperation,
3127
+ yAxisColumns: normalizeColumns(yAxisColumn),
3128
+ yAxisJoinOperation
3129
+ });
3130
+ }
3131
+ async getTable(options) {
3132
+ const {
3133
+ filterOwner
3134
+ } = options,
3135
+ params = _objectWithoutPropertiesLoose(options, _excluded);
3136
+ const {
3137
+ columns,
3138
+ searchFilterColumn,
3139
+ searchFilterText,
3140
+ sortBy,
3141
+ sortDirection,
3142
+ sortByColumnType,
3143
+ offset = 0,
3144
+ limit = 10
3145
+ } = params;
3146
+ if (!this._features.length) {
3147
+ return {
3148
+ rows: [],
3149
+ totalCount: 0
3150
+ };
3151
+ }
3152
+ // Filter.
3153
+ let filteredFeatures = this._getFilteredFeatures(filterOwner);
3154
+ // Search.
3155
+ // TODO: Could we get the same behavior by applying filters in loadTiles()?
3156
+ if (searchFilterColumn && searchFilterText) {
3157
+ filteredFeatures = filteredFeatures.filter(row => row[searchFilterColumn] && String(row[searchFilterColumn]).toLowerCase().includes(String(searchFilterText).toLowerCase()));
3158
+ }
3159
+ // Sort.
3160
+ let rows = applySorting(filteredFeatures, {
3161
+ sortBy,
3162
+ sortByDirection: sortDirection,
3163
+ sortByColumnType
3164
+ });
3165
+ const totalCount = rows.length;
3166
+ // Offset and limit.
3167
+ rows = rows.slice(Math.min(offset, totalCount), Math.min(offset + limit, totalCount));
3168
+ // Select columns.
3169
+ rows = rows.map(srcRow => {
3170
+ const dstRow = {};
3171
+ for (const column of columns) {
3172
+ dstRow[column] = srcRow[column];
3173
+ }
3174
+ return dstRow;
3175
+ });
3176
+ return {
3177
+ rows,
3178
+ totalCount
3179
+ };
3180
+ }
3181
+ async getTimeSeries({
3182
+ column,
3183
+ stepSize,
3184
+ operation,
3185
+ operationColumn,
3186
+ joinOperation,
3187
+ filterOwner
3188
+ }) {
3189
+ if (!this._features.length) {
3190
+ return {
3191
+ rows: []
3192
+ };
3193
+ }
3194
+ const filteredFeatures = this._getFilteredFeatures(filterOwner);
3195
+ assertColumn(this._features, column, operationColumn);
3196
+ const rows = groupValuesByDateColumn({
3197
+ data: filteredFeatures,
3198
+ valuesColumns: normalizeColumns(operationColumn || column),
3199
+ keysColumn: column,
3200
+ groupType: stepSize,
3201
+ operation,
3202
+ joinOperation
3203
+ }) || [];
3204
+ return {
3205
+ rows
3206
+ };
3207
+ }
3208
+ async getRange({
3209
+ column,
3210
+ filterOwner
3211
+ }) {
3212
+ if (!this._features.length) {
3213
+ // TODO: Is this the only nullable response in the Widgets API? If so,
3214
+ // can we do something more consistent?
3215
+ return null;
3216
+ }
3217
+ assertColumn(this._features, column);
3218
+ const filteredFeatures = this._getFilteredFeatures(filterOwner);
3219
+ return {
3220
+ min: aggregationFunctions.min(filteredFeatures, column),
3221
+ max: aggregationFunctions.max(filteredFeatures, column)
3222
+ };
3223
+ }
3224
+ /****************************************************************************
3225
+ * INTERNAL
3226
+ */
3227
+ _getFilteredFeatures(filterOwner) {
3228
+ return applyFilters(this._features, getApplicableFilters(filterOwner, this.props.filters), this.props.filtersLogicalOperator || 'and');
3229
+ }
3230
+ }
3231
+ function assertColumn(features, ...columnArgs) {
3232
+ // TODO(cleanup): Can drop support for multiple column shapes here?
3233
+ // Due to the multiple column shape, we normalise it as an array with normalizeColumns
3234
+ const columns = Array.from(new Set(columnArgs.map(normalizeColumns).flat()));
3235
+ const featureKeys = Object.keys(features[0]);
3236
+ const invalidColumns = columns.filter(column => !featureKeys.includes(column));
3237
+ if (invalidColumns.length) {
3238
+ throw new InvalidColumnError(`Missing column(s): ${invalidColumns.join(', ')}`);
3239
+ }
3240
+ }
3241
+ function normalizeColumns(columns) {
3242
+ return Array.isArray(columns) ? columns : typeof columns === 'string' ? [columns] : [];
3243
+ }
3244
+
3245
+ const h3QuerySource = async function h3QuerySource(options) {
3246
+ const {
3247
+ aggregationExp,
3248
+ aggregationResLevel = DEFAULT_AGGREGATION_RES_LEVEL_H3,
3249
+ sqlQuery,
3250
+ spatialDataColumn = 'h3',
3251
+ queryParameters,
3252
+ filters
3253
+ } = options;
3254
+ const urlParameters = {
3255
+ aggregationExp,
3256
+ spatialDataColumn,
3257
+ spatialDataType: 'h3',
3258
+ q: sqlQuery
3259
+ };
3260
+ if (aggregationResLevel) {
3261
+ urlParameters.aggregationResLevel = String(aggregationResLevel);
3262
+ }
3263
+ if (queryParameters) {
3264
+ urlParameters.queryParameters = queryParameters;
3265
+ }
3266
+ if (filters) {
3267
+ urlParameters.filters = filters;
3268
+ }
3269
+ return baseSource('query', options, urlParameters).then(result => _extends({}, result, {
3270
+ widgetSource: new WidgetQuerySource(_extends({}, options, {
3271
+ // NOTE: passing redundant spatialDataColumn here to apply the default value 'h3'
3272
+ spatialDataColumn,
3273
+ spatialDataType: 'h3'
3274
+ }))
3275
+ }));
3276
+ };
3277
+
3278
+ const h3TableSource = async function h3TableSource(options) {
3279
+ const {
3280
+ aggregationExp,
3281
+ aggregationResLevel = DEFAULT_AGGREGATION_RES_LEVEL_H3,
3282
+ spatialDataColumn = 'h3',
3283
+ tableName,
3284
+ filters
3285
+ } = options;
3286
+ const urlParameters = {
3287
+ aggregationExp,
3288
+ name: tableName,
3289
+ spatialDataColumn,
3290
+ spatialDataType: 'h3'
3291
+ };
3292
+ if (aggregationResLevel) {
3293
+ urlParameters.aggregationResLevel = String(aggregationResLevel);
3294
+ }
3295
+ if (filters) {
3296
+ urlParameters.filters = filters;
3297
+ }
3298
+ return baseSource('table', options, urlParameters).then(result => _extends({}, result, {
3299
+ widgetSource: new WidgetTableSource(_extends({}, options, {
3300
+ // NOTE: passing redundant spatialDataColumn here to apply the default value 'h3'
3301
+ spatialDataColumn,
3302
+ spatialDataType: 'h3'
3303
+ }))
3304
+ }));
3305
+ };
3306
+
3307
+ function getTileFormat(tilejson) {
3308
+ const tileParams = new URL(tilejson.tiles[0]).searchParams;
3309
+ return tileParams.get('formatTiles') === 'mvt' ? TileFormat.MVT : TileFormat.BINARY;
3310
+ }
3311
+
3312
+ const h3TilesetSource = async function h3TilesetSource(options) {
3313
+ const {
3314
+ tableName,
3315
+ spatialDataColumn = 'h3'
3316
+ } = options;
3317
+ const urlParameters = {
3318
+ name: tableName
3319
+ };
3320
+ return baseSource('tileset', options, urlParameters).then(result => _extends({}, result, {
3321
+ widgetSource: new WidgetTilesetSource(_extends({}, options, {
3322
+ tileFormat: getTileFormat(result),
3323
+ spatialDataColumn,
3324
+ spatialDataType: 'h3'
3325
+ }))
3326
+ }));
3327
+ };
3328
+
3329
+ // deck.gl
3330
+ // SPDX-License-Identifier: MIT
3331
+ // Copyright (c) vis.gl contributors
3332
+ const rasterSource = async function rasterSource(options) {
3333
+ const {
3334
+ tableName,
3335
+ filters
3336
+ } = options;
3337
+ const urlParameters = {
3338
+ name: tableName
3339
+ };
3340
+ if (filters) {
3341
+ urlParameters.filters = filters;
3342
+ }
3343
+ return baseSource('raster', options, urlParameters);
3344
+ };
3345
+
3346
+ const quadbinQuerySource = async function quadbinQuerySource(options) {
3347
+ const {
3348
+ aggregationExp,
3349
+ aggregationResLevel = DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN,
3350
+ sqlQuery,
3351
+ spatialDataColumn = 'quadbin',
3352
+ queryParameters,
3353
+ filters
3354
+ } = options;
3355
+ const urlParameters = {
3356
+ aggregationExp,
3357
+ q: sqlQuery,
3358
+ spatialDataColumn,
3359
+ spatialDataType: 'quadbin'
3360
+ };
3361
+ if (aggregationResLevel) {
3362
+ urlParameters.aggregationResLevel = String(aggregationResLevel);
3363
+ }
3364
+ if (queryParameters) {
3365
+ urlParameters.queryParameters = queryParameters;
3366
+ }
3367
+ if (filters) {
3368
+ urlParameters.filters = filters;
3369
+ }
3370
+ return baseSource('query', options, urlParameters).then(result => _extends({}, result, {
3371
+ widgetSource: new WidgetQuerySource(_extends({}, options, {
3372
+ // NOTE: passing redundant spatialDataColumn here to apply the default value 'quadbin'
3373
+ spatialDataColumn,
3374
+ spatialDataType: 'quadbin'
3375
+ }))
3376
+ }));
3377
+ };
3378
+
3379
+ const quadbinTableSource = async function quadbinTableSource(options) {
3380
+ const {
3381
+ aggregationExp,
3382
+ aggregationResLevel = DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN,
3383
+ spatialDataColumn = 'quadbin',
3384
+ tableName,
3385
+ filters
3386
+ } = options;
3387
+ const urlParameters = {
3388
+ aggregationExp,
3389
+ name: tableName,
3390
+ spatialDataColumn,
3391
+ spatialDataType: 'quadbin'
3392
+ };
3393
+ if (aggregationResLevel) {
3394
+ urlParameters.aggregationResLevel = String(aggregationResLevel);
3395
+ }
3396
+ if (filters) {
3397
+ urlParameters.filters = filters;
3398
+ }
3399
+ return baseSource('table', options, urlParameters).then(result => _extends({}, result, {
3400
+ widgetSource: new WidgetTableSource(_extends({}, options, {
3401
+ // NOTE: passing redundant spatialDataColumn here to apply the default value 'quadbin'
3402
+ spatialDataColumn,
3403
+ spatialDataType: 'quadbin'
3404
+ }))
3405
+ }));
3406
+ };
3407
+
3408
+ const quadbinTilesetSource = async function quadbinTilesetSource(options) {
1586
3409
  const {
1587
- tableName
3410
+ tableName,
3411
+ spatialDataColumn = 'quadbin'
1588
3412
  } = options;
1589
3413
  const urlParameters = {
1590
3414
  name: tableName
1591
3415
  };
1592
- return baseSource('tileset', options, urlParameters);
3416
+ return baseSource('tileset', options, urlParameters).then(result => _extends({}, result, {
3417
+ widgetSource: new WidgetTilesetSource(_extends({}, options, {
3418
+ tileFormat: getTileFormat(result),
3419
+ spatialDataColumn,
3420
+ spatialDataType: 'quadbin'
3421
+ }))
3422
+ }));
1593
3423
  };
1594
3424
 
1595
3425
  const vectorQuerySource = async function vectorQuerySource(options) {
1596
3426
  const {
1597
3427
  columns,
1598
3428
  filters,
1599
- spatialDataColumn = 'geom',
3429
+ spatialDataColumn = DEFAULT_GEO_COLUMN,
1600
3430
  sqlQuery,
1601
3431
  tileResolution = DEFAULT_TILE_RESOLUTION,
1602
3432
  queryParameters,
@@ -1622,6 +3452,7 @@ const vectorQuerySource = async function vectorQuerySource(options) {
1622
3452
  }
1623
3453
  return baseSource('query', options, urlParameters).then(result => _extends({}, result, {
1624
3454
  widgetSource: new WidgetQuerySource(_extends({}, options, {
3455
+ spatialDataColumn,
1625
3456
  spatialDataType: 'geo'
1626
3457
  }))
1627
3458
  }));
@@ -1631,7 +3462,7 @@ const vectorTableSource = async function vectorTableSource(options) {
1631
3462
  const {
1632
3463
  columns,
1633
3464
  filters,
1634
- spatialDataColumn = 'geom',
3465
+ spatialDataColumn = DEFAULT_GEO_COLUMN,
1635
3466
  tableName,
1636
3467
  tileResolution = DEFAULT_TILE_RESOLUTION,
1637
3468
  aggregationExp
@@ -1653,20 +3484,27 @@ const vectorTableSource = async function vectorTableSource(options) {
1653
3484
  }
1654
3485
  return baseSource('table', options, urlParameters).then(result => _extends({}, result, {
1655
3486
  widgetSource: new WidgetTableSource(_extends({}, options, {
3487
+ spatialDataColumn,
1656
3488
  spatialDataType: 'geo'
1657
3489
  }))
1658
3490
  }));
1659
3491
  };
1660
3492
 
1661
- // deck.gl
1662
3493
  const vectorTilesetSource = async function vectorTilesetSource(options) {
1663
3494
  const {
1664
- tableName
3495
+ tableName,
3496
+ spatialDataColumn = DEFAULT_GEO_COLUMN
1665
3497
  } = options;
1666
3498
  const urlParameters = {
1667
3499
  name: tableName
1668
3500
  };
1669
- return baseSource('tileset', options, urlParameters);
3501
+ return baseSource('tileset', options, urlParameters).then(result => _extends({}, result, {
3502
+ widgetSource: new WidgetTilesetSource(_extends({}, options, {
3503
+ tileFormat: getTileFormat(result),
3504
+ spatialDataColumn,
3505
+ spatialDataType: 'geo'
3506
+ }))
3507
+ }));
1670
3508
  };
1671
3509
 
1672
3510
  const query = async function query(options) {
@@ -1711,5 +3549,5 @@ const query = async function query(options) {
1711
3549
  });
1712
3550
  };
1713
3551
 
1714
- export { ApiVersion, CartoAPIError, DEFAULT_API_BASE_URL, FilterType, SOURCE_DEFAULTS, WidgetBaseSource, WidgetQuerySource, WidgetTableSource, addFilter, boundaryQuerySource, boundaryTableSource, buildPublicMapUrl, buildStatsUrl, clearFilters, createPolygonSpatialFilter, createViewportSpatialFilter, getClient, getFilter, h3QuerySource, h3TableSource, h3TilesetSource, hasFilter, quadbinQuerySource, quadbinTableSource, quadbinTilesetSource, query, rasterSource, removeFilter, requestWithParameters, setClient, vectorQuerySource, vectorTableSource, vectorTilesetSource };
3552
+ export { ApiVersion, CartoAPIError, DEFAULT_API_BASE_URL, FEATURE_GEOM_PROPERTY, FilterType, Provider, SOURCE_DEFAULTS, SpatialIndex, TileFormat, WidgetQuerySource, WidgetRemoteSource, WidgetTableSource, WidgetTilesetSource, 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 };
1715
3553
  //# sourceMappingURL=api-client.modern.js.map