@carto/api-client 0.4.3 → 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 (93) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/build/api/query.d.ts +1 -1
  3. package/build/api-client.cjs +2388 -261
  4. package/build/api-client.cjs.map +1 -1
  5. package/build/api-client.modern.js +2237 -262
  6. package/build/api-client.modern.js.map +1 -1
  7. package/build/constants.d.ts +22 -0
  8. package/build/filters/Filter.d.ts +13 -0
  9. package/build/filters/FilterTypes.d.ts +3 -0
  10. package/build/filters/geosjonFeatures.d.ts +8 -0
  11. package/build/filters/index.d.ts +6 -0
  12. package/build/filters/tileFeatures.d.ts +20 -0
  13. package/build/filters/tileFeaturesGeometries.d.ts +13 -0
  14. package/build/filters/tileFeaturesSpatialIndex.d.ts +10 -0
  15. package/build/index.d.ts +4 -0
  16. package/build/models/index.d.ts +1 -1
  17. package/build/models/model.d.ts +7 -1
  18. package/build/operations/aggregation.d.ts +8 -0
  19. package/build/operations/applySorting.d.ts +20 -0
  20. package/build/operations/groupBy.d.ts +15 -0
  21. package/build/operations/groupByDate.d.ts +11 -0
  22. package/build/operations/histogram.d.ts +13 -0
  23. package/build/operations/index.d.ts +6 -0
  24. package/build/operations/scatterPlot.d.ts +14 -0
  25. package/build/sources/h3-tileset-source.d.ts +2 -1
  26. package/build/sources/index.d.ts +1 -1
  27. package/build/sources/quadbin-tileset-source.d.ts +2 -1
  28. package/build/sources/types.d.ts +36 -41
  29. package/build/sources/vector-tileset-source.d.ts +2 -1
  30. package/build/spatial-index.d.ts +8 -0
  31. package/build/types-internal.d.ts +4 -0
  32. package/build/types.d.ts +61 -1
  33. package/build/utils/dateUtils.d.ts +10 -0
  34. package/build/utils/getTileFormat.d.ts +3 -0
  35. package/build/utils/makeIntervalComplete.d.ts +2 -0
  36. package/build/utils/transformTileCoordsToWGS84.d.ts +8 -0
  37. package/build/utils/transformToTileCoords.d.ts +9 -0
  38. package/build/utils.d.ts +1 -1
  39. package/build/widget-sources/index.d.ts +2 -1
  40. package/build/widget-sources/types.d.ts +40 -23
  41. package/build/widget-sources/widget-query-source.d.ts +2 -2
  42. package/build/widget-sources/widget-remote-source.d.ts +18 -0
  43. package/build/widget-sources/{widget-base-source.d.ts → widget-source.d.ts} +16 -41
  44. package/build/widget-sources/widget-table-source.d.ts +2 -2
  45. package/build/widget-sources/widget-tileset-source.d.ts +67 -0
  46. package/package.json +36 -35
  47. package/src/api/query.ts +1 -2
  48. package/src/constants.ts +25 -0
  49. package/src/filters/Filter.ts +169 -0
  50. package/src/filters/FilterTypes.ts +109 -0
  51. package/src/filters/geosjonFeatures.ts +32 -0
  52. package/src/filters/index.ts +6 -0
  53. package/src/filters/tileFeatures.ts +56 -0
  54. package/src/filters/tileFeaturesGeometries.ts +444 -0
  55. package/src/filters/tileFeaturesSpatialIndex.ts +119 -0
  56. package/src/index.ts +6 -0
  57. package/src/models/index.ts +1 -1
  58. package/src/models/model.ts +47 -24
  59. package/src/operations/aggregation.ts +154 -0
  60. package/src/operations/applySorting.ts +109 -0
  61. package/src/operations/groupBy.ts +59 -0
  62. package/src/operations/groupByDate.ts +98 -0
  63. package/src/operations/histogram.ts +66 -0
  64. package/src/operations/index.ts +6 -0
  65. package/src/operations/scatterPlot.ts +50 -0
  66. package/src/sources/h3-query-source.ts +7 -1
  67. package/src/sources/h3-table-source.ts +6 -1
  68. package/src/sources/h3-tileset-source.ts +18 -6
  69. package/src/sources/index.ts +1 -1
  70. package/src/sources/quadbin-query-source.ts +6 -1
  71. package/src/sources/quadbin-table-source.ts +6 -1
  72. package/src/sources/quadbin-tileset-source.ts +18 -6
  73. package/src/sources/raster-source.ts +1 -0
  74. package/src/sources/types.ts +41 -45
  75. package/src/sources/vector-query-source.ts +10 -3
  76. package/src/sources/vector-table-source.ts +10 -3
  77. package/src/sources/vector-tileset-source.ts +19 -6
  78. package/src/spatial-index.ts +111 -0
  79. package/src/types-internal.ts +6 -0
  80. package/src/types.ts +60 -2
  81. package/src/utils/dateUtils.ts +28 -0
  82. package/src/utils/getTileFormat.ts +9 -0
  83. package/src/utils/makeIntervalComplete.ts +17 -0
  84. package/src/utils/transformTileCoordsToWGS84.ts +77 -0
  85. package/src/utils/transformToTileCoords.ts +85 -0
  86. package/src/utils.ts +9 -6
  87. package/src/widget-sources/index.ts +2 -1
  88. package/src/widget-sources/types.ts +42 -23
  89. package/src/widget-sources/widget-query-source.ts +6 -3
  90. package/src/widget-sources/{widget-base-source.ts → widget-remote-source.ts} +169 -144
  91. package/src/widget-sources/widget-source.ts +160 -0
  92. package/src/widget-sources/widget-table-source.ts +6 -3
  93. package/src/widget-sources/widget-tileset-source.ts +396 -0
@@ -3,12 +3,10 @@ var bboxPolygon = require('@turf/bbox-polygon');
3
3
  var union = require('@turf/union');
4
4
  var invariant = require('@turf/invariant');
5
5
  var helpers = require('@turf/helpers');
6
-
7
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
8
-
9
- var bboxClip__default = /*#__PURE__*/_interopDefaultLegacy(bboxClip);
10
- var bboxPolygon__default = /*#__PURE__*/_interopDefaultLegacy(bboxPolygon);
11
- var union__default = /*#__PURE__*/_interopDefaultLegacy(union);
6
+ var intersects = require('@turf/boolean-intersects');
7
+ var booleanWithin = require('@turf/boolean-within');
8
+ var intersect = require('@turf/intersect');
9
+ var h3Js = require('h3-js');
12
10
 
13
11
  /**
14
12
  * @internal
@@ -67,6 +65,31 @@ exports.ApiVersion = void 0;
67
65
  })(exports.ApiVersion || (exports.ApiVersion = {}));
68
66
  /** @internalRemarks Source: @carto/constants, @deck.gl/carto */
69
67
  const DEFAULT_API_BASE_URL = 'https://gcp-us-east1.api.carto.com';
68
+ /** @internalRemarks Source: @carto/react-core */
69
+ exports.TileFormat = void 0;
70
+ (function (TileFormat) {
71
+ TileFormat["MVT"] = "mvt";
72
+ TileFormat["JSON"] = "json";
73
+ TileFormat["GEOJSON"] = "geojson";
74
+ TileFormat["BINARY"] = "binary";
75
+ })(exports.TileFormat || (exports.TileFormat = {}));
76
+ /** @internalRemarks Source: @carto/react-core */
77
+ exports.SpatialIndex = void 0;
78
+ (function (SpatialIndex) {
79
+ SpatialIndex["H3"] = "h3";
80
+ SpatialIndex["S2"] = "s2";
81
+ SpatialIndex["QUADBIN"] = "quadbin";
82
+ })(exports.SpatialIndex || (exports.SpatialIndex = {}));
83
+ /** @internalRemarks Source: @carto/react-core */
84
+ exports.Provider = void 0;
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
+ })(exports.Provider || (exports.Provider = {}));
70
93
 
71
94
  const FILTER_TYPES = new Set(Object.values(exports.FilterType));
72
95
  const isFilterType = type => FILTER_TYPES.has(type);
@@ -110,7 +133,7 @@ function normalizeObjectKeys(el) {
110
133
  }, {});
111
134
  }
112
135
  /** @internalRemarks Source: @carto/react-core */
113
- function assert(condition, message) {
136
+ function assert$1(condition, message) {
114
137
  if (!condition) {
115
138
  throw new Error(message);
116
139
  }
@@ -245,7 +268,7 @@ function createViewportSpatialFilter(viewport) {
245
268
  if (_isGlobalViewport(viewport)) {
246
269
  return;
247
270
  }
248
- return createPolygonSpatialFilter(bboxPolygon__default["default"](viewport).geometry);
271
+ return createPolygonSpatialFilter(bboxPolygon(viewport).geometry);
249
272
  }
250
273
  /**
251
274
  * Returns a {@link SpatialFilter} for a given {@link Polygon} or
@@ -277,23 +300,23 @@ function _isGlobalViewport(viewport) {
277
300
  */
278
301
  function _normalizeGeometry(geometry) {
279
302
  const WORLD = [-180, -90, +180, +90];
280
- const worldClip = _clean(bboxClip__default["default"](geometry, WORLD).geometry);
303
+ const worldClip = _clean(bboxClip(geometry, WORLD).geometry);
281
304
  const geometryTxWest = _tx(geometry, 360);
282
305
  const geometryTxEast = _tx(geometry, -360);
283
306
  let result = worldClip;
284
307
  if (result && geometryTxWest) {
285
- const worldWestClip = _clean(bboxClip__default["default"](geometryTxWest, WORLD).geometry);
308
+ const worldWestClip = _clean(bboxClip(geometryTxWest, WORLD).geometry);
286
309
  if (worldWestClip) {
287
310
  const collection = helpers.featureCollection([helpers.feature(result), helpers.feature(worldWestClip)]);
288
- const merged = union__default["default"](collection);
311
+ const merged = union(collection);
289
312
  result = merged ? _clean(merged.geometry) : result;
290
313
  }
291
314
  }
292
315
  if (result && geometryTxEast) {
293
- const worldEastClip = _clean(bboxClip__default["default"](geometryTxEast, WORLD).geometry);
316
+ const worldEastClip = _clean(bboxClip(geometryTxEast, WORLD).geometry);
294
317
  if (worldEastClip) {
295
318
  const collection = helpers.featureCollection([helpers.feature(result), helpers.feature(worldEastClip)]);
296
- const merged = union__default["default"](collection);
319
+ const merged = union(collection);
297
320
  result = merged ? _clean(merged.geometry) : result;
298
321
  }
299
322
  }
@@ -486,6 +509,8 @@ function formatErrorKey(key) {
486
509
  }
487
510
 
488
511
  // deck.gl
512
+ // SPDX-License-Identifier: MIT
513
+ // Copyright (c) vis.gl contributors
489
514
  const requestWithParameters = function (_ref) {
490
515
  let {
491
516
  baseUrl,
@@ -617,6 +642,8 @@ function excludeURLParameters(baseUrlString, parameters) {
617
642
  }
618
643
 
619
644
  // deck.gl
645
+ // SPDX-License-Identifier: MIT
646
+ // Copyright (c) vis.gl contributors
620
647
  const baseSource = function (endpoint, options, urlParameters) {
621
648
  try {
622
649
  const {
@@ -712,6 +739,8 @@ const SOURCE_DEFAULTS = {
712
739
  };
713
740
 
714
741
  // deck.gl
742
+ // SPDX-License-Identifier: MIT
743
+ // Copyright (c) vis.gl contributors
715
744
  const boundaryQuerySource = function (options) {
716
745
  try {
717
746
  const {
@@ -741,6 +770,8 @@ const boundaryQuerySource = function (options) {
741
770
  };
742
771
 
743
772
  // deck.gl
773
+ // SPDX-License-Identifier: MIT
774
+ // Copyright (c) vis.gl contributors
744
775
  const boundaryTableSource = function (options) {
745
776
  try {
746
777
  const {
@@ -866,10 +897,10 @@ const REQUEST_GET_MAX_URL_LENGTH = 2048;
866
897
  * @internalRemarks Source: @carto/react-api
867
898
  */
868
899
  function executeModel(props) {
869
- assert(props.source, 'executeModel: missing source');
870
- assert(props.model, 'executeModel: missing model');
871
- assert(props.params, 'executeModel: missing params');
872
- assert(AVAILABLE_MODELS.includes(props.model), `executeModel: model provided isn't valid. Available models: ${AVAILABLE_MODELS.join(', ')}`);
900
+ assert$1(props.source, 'executeModel: missing source');
901
+ assert$1(props.model, 'executeModel: missing model');
902
+ assert$1(props.params, 'executeModel: missing params');
903
+ assert$1(AVAILABLE_MODELS.includes(props.model), `executeModel: model provided isn't valid. Available models: ${AVAILABLE_MODELS.join(', ')}`);
873
904
  const {
874
905
  model,
875
906
  source,
@@ -884,50 +915,52 @@ function executeModel(props) {
884
915
  connectionName,
885
916
  clientId
886
917
  } = source;
887
- assert(apiBaseUrl, 'executeModel: missing apiBaseUrl');
888
- assert(accessToken, 'executeModel: missing accessToken');
889
- assert(apiVersion === V3, 'executeModel: SQL Model API requires CARTO 3+');
890
- assert(type !== 'tileset', 'executeModel: Tilesets not supported');
918
+ assert$1(apiBaseUrl, 'executeModel: missing apiBaseUrl');
919
+ assert$1(accessToken, 'executeModel: missing accessToken');
920
+ assert$1(apiVersion === V3, 'executeModel: SQL Model API requires CARTO 3+');
921
+ assert$1(type !== 'tileset', 'executeModel: Tilesets not supported');
891
922
  let url = `${apiBaseUrl}/v3/sql/${connectionName}/model/${model}`;
892
923
  const {
893
924
  data,
894
925
  filters,
895
926
  filtersLogicalOperator = 'and',
896
- geoColumn = DEFAULT_GEO_COLUMN
927
+ spatialDataType = 'geo',
928
+ spatialFiltersMode = 'intersects',
929
+ spatialFiltersResolution = 0
897
930
  } = source;
898
- const queryParameters = source.queryParameters ? JSON.stringify(source.queryParameters) : '';
899
931
  const queryParams = {
900
932
  type,
901
933
  client: clientId,
902
934
  source: data,
903
- params: JSON.stringify(params),
904
- queryParameters,
905
- filters: JSON.stringify(filters),
935
+ params,
936
+ queryParameters: source.queryParameters || '',
937
+ filters,
906
938
  filtersLogicalOperator
907
939
  };
940
+ const spatialDataColumn = source.spatialDataColumn || DEFAULT_GEO_COLUMN;
908
941
  // Picking Model API requires 'spatialDataColumn'.
909
942
  if (model === 'pick') {
910
- queryParams.spatialDataColumn = geoColumn;
943
+ queryParams.spatialDataColumn = spatialDataColumn;
911
944
  }
912
- // API supports multiple filters, we apply it only to geoColumn
945
+ // API supports multiple filters, we apply it only to spatialDataColumn
913
946
  const spatialFilters = source.spatialFilter ? {
914
- [geoColumn]: source.spatialFilter
947
+ [spatialDataColumn]: source.spatialFilter
915
948
  } : undefined;
916
949
  if (spatialFilters) {
917
- queryParams.spatialFilters = JSON.stringify(spatialFilters);
950
+ queryParams.spatialFilters = spatialFilters;
951
+ queryParams.spatialDataColumn = spatialDataColumn;
952
+ queryParams.spatialDataType = spatialDataType;
918
953
  }
919
- const urlWithSearchParams = url + '?' + new URLSearchParams(queryParams).toString();
954
+ if (spatialDataType !== 'geo') {
955
+ if (spatialFiltersResolution > 0) {
956
+ queryParams.spatialFiltersResolution = spatialFiltersResolution;
957
+ }
958
+ queryParams.spatialFiltersMode = spatialFiltersMode;
959
+ }
960
+ const urlWithSearchParams = url + '?' + objectToURLSearchParams(queryParams).toString();
920
961
  const isGet = urlWithSearchParams.length <= REQUEST_GET_MAX_URL_LENGTH;
921
962
  if (isGet) {
922
963
  url = urlWithSearchParams;
923
- } else {
924
- // undo the JSON.stringify, @TODO find a better pattern
925
- queryParams.params = params;
926
- queryParams.filters = filters;
927
- queryParams.queryParameters = source.queryParameters;
928
- if (spatialFilters) {
929
- queryParams.spatialFilters = spatialFilters;
930
- }
931
964
  }
932
965
  return makeCall({
933
966
  url,
@@ -941,17 +974,74 @@ function executeModel(props) {
941
974
  }
942
975
  });
943
976
  }
977
+ function objectToURLSearchParams(object) {
978
+ const params = new URLSearchParams();
979
+ for (const key in object) {
980
+ if (isPureObject(object[key])) {
981
+ params.append(key, JSON.stringify(object[key]));
982
+ } else if (Array.isArray(object[key])) {
983
+ params.append(key, JSON.stringify(object[key]));
984
+ } else if (object[key] === null) {
985
+ params.append(key, 'null');
986
+ } else if (object[key] !== undefined) {
987
+ params.append(key, String(object[key]));
988
+ }
989
+ }
990
+ return params;
991
+ }
992
+
993
+ const DEFAULT_TILE_SIZE = 512;
994
+ const QUADBIN_ZOOM_MAX_OFFSET = 4;
995
+ function getSpatialFiltersResolution(source, viewState) {
996
+ const dataResolution = source.dataResolution ?? Number.MAX_VALUE;
997
+ const aggregationResLevel = source.aggregationResLevel ?? (source.spatialDataType === 'h3' ? DEFAULT_AGGREGATION_RES_LEVEL_H3 : DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN);
998
+ const aggregationResLevelOffset = Math.max(0, Math.floor(aggregationResLevel));
999
+ const currentZoomInt = Math.ceil(viewState.zoom);
1000
+ if (source.spatialDataType === 'h3') {
1001
+ const tileSize = DEFAULT_TILE_SIZE;
1002
+ const maxResolutionForZoom = maxH3SpatialFiltersResolutions.find(_ref => {
1003
+ let [zoom] = _ref;
1004
+ return zoom === currentZoomInt;
1005
+ })?.[1] ?? Math.max(0, currentZoomInt - 3);
1006
+ const maxSpatialFiltersResolution = maxResolutionForZoom ? Math.min(dataResolution, maxResolutionForZoom) : dataResolution;
1007
+ const hexagonResolution = getHexagonResolution(viewState, tileSize) + aggregationResLevelOffset;
1008
+ return Math.min(hexagonResolution, maxSpatialFiltersResolution);
1009
+ }
1010
+ if (source.spatialDataType === 'quadbin') {
1011
+ const maxResolutionForZoom = currentZoomInt + QUADBIN_ZOOM_MAX_OFFSET;
1012
+ const maxSpatialFiltersResolution = Math.min(dataResolution, maxResolutionForZoom);
1013
+ const quadsResolution = Math.floor(viewState.zoom) + aggregationResLevelOffset;
1014
+ return Math.min(quadsResolution, maxSpatialFiltersResolution);
1015
+ }
1016
+ return undefined;
1017
+ }
1018
+ const maxH3SpatialFiltersResolutions = [[20, 14], [19, 13], [18, 12], [17, 11], [16, 10], [15, 9], [14, 8], [13, 7], [12, 7], [11, 7], [10, 6], [9, 6], [8, 5], [7, 4], [6, 4], [5, 3], [4, 2], [3, 1], [2, 1], [1, 0]];
1019
+ // stolen from https://github.com/visgl/deck.gl/blob/master/modules/carto/src/layers/h3-tileset-2d.ts
1020
+ // Relative scale factor (0 = no biasing, 2 = a few hexagons cover view)
1021
+ const BIAS = 2;
1022
+ // Resolution conversion function. Takes a WebMercatorViewport and returns
1023
+ // a H3 resolution such that the screen space size of the hexagons is
1024
+ // similar
1025
+ function getHexagonResolution(viewport, tileSize) {
1026
+ // Difference in given tile size compared to deck's internal 512px tile size,
1027
+ // expressed as an offset to the viewport zoom.
1028
+ const zoomOffset = Math.log2(tileSize / DEFAULT_TILE_SIZE);
1029
+ const hexagonScaleFactor = 2 / 3 * (viewport.zoom - zoomOffset);
1030
+ const latitudeScaleFactor = Math.log(1 / Math.cos(Math.PI * viewport.latitude / 180));
1031
+ // Clip and bias
1032
+ return Math.max(0, Math.floor(hexagonScaleFactor + latitudeScaleFactor - BIAS));
1033
+ }
944
1034
 
945
1035
  /**
946
1036
  * Source for Widget API requests on a data source defined by a SQL query.
947
1037
  *
948
1038
  * Abstract class. Use {@link WidgetQuerySource} or {@link WidgetTableSource}.
949
1039
  */
950
- class WidgetBaseSource {
1040
+ class WidgetSource {
951
1041
  constructor(props) {
952
1042
  this.props = void 0;
953
1043
  this.props = {
954
- ...WidgetBaseSource.defaultProps,
1044
+ ...WidgetSource.defaultProps,
955
1045
  ...props
956
1046
  };
957
1047
  }
@@ -965,22 +1055,44 @@ class WidgetBaseSource {
965
1055
  connectionName: props.connectionName,
966
1056
  filters: getApplicableFilters(owner, props.filters),
967
1057
  filtersLogicalOperator: props.filtersLogicalOperator,
968
- geoColumn: props.geoColumn
1058
+ spatialDataType: props.spatialDataType,
1059
+ spatialDataColumn: props.spatialDataColumn,
1060
+ dataResolution: props.dataResolution
969
1061
  };
970
1062
  }
971
- /****************************************************************************
972
- * CATEGORIES
973
- */
974
- /**
975
- * Returns a list of labeled datapoints for categorical data. Suitable for
976
- * charts including grouped bar charts, pie charts, and tree charts.
977
- */
1063
+ _getSpatialFiltersResolution(source, spatialFilter, referenceViewState) {
1064
+ // spatialFiltersResolution applies only to spatial index sources.
1065
+ if (!spatialFilter || source.spatialDataType === 'geo') {
1066
+ return;
1067
+ }
1068
+ if (!referenceViewState) {
1069
+ throw new Error('Missing required option, "spatialIndexReferenceViewState".');
1070
+ }
1071
+ return getSpatialFiltersResolution(source, referenceViewState);
1072
+ }
1073
+ }
1074
+ WidgetSource.defaultProps = {
1075
+ apiVersion: exports.ApiVersion.V3,
1076
+ apiBaseUrl: DEFAULT_API_BASE_URL,
1077
+ clientId: getClient(),
1078
+ filters: {},
1079
+ filtersLogicalOperator: 'and'
1080
+ };
1081
+
1082
+ /**
1083
+ * Source for Widget API requests.
1084
+ *
1085
+ * Abstract class. Use {@link WidgetQuerySource} or {@link WidgetTableSource}.
1086
+ */
1087
+ class WidgetRemoteSource extends WidgetSource {
978
1088
  getCategories(options) {
979
1089
  try {
980
1090
  const _this = this;
981
1091
  const {
982
1092
  filterOwner,
983
1093
  spatialFilter,
1094
+ spatialFiltersMode,
1095
+ spatialIndexReferenceViewState,
984
1096
  abortController,
985
1097
  ...params
986
1098
  } = options;
@@ -989,10 +1101,14 @@ class WidgetBaseSource {
989
1101
  operation,
990
1102
  operationColumn
991
1103
  } = params;
1104
+ const source = _this.getModelSource(filterOwner);
1105
+ const spatialFiltersResolution = _this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
992
1106
  return Promise.resolve(executeModel({
993
1107
  model: 'category',
994
1108
  source: {
995
- ..._this.getModelSource(filterOwner),
1109
+ ...source,
1110
+ spatialFiltersResolution,
1111
+ spatialFiltersMode,
996
1112
  spatialFilter
997
1113
  },
998
1114
  params: {
@@ -1008,23 +1124,14 @@ class WidgetBaseSource {
1008
1124
  return Promise.reject(e);
1009
1125
  }
1010
1126
  }
1011
- /****************************************************************************
1012
- * FEATURES
1013
- */
1014
- /**
1015
- * Given a list of feature IDs (as found in `_carto_feature_id`) returns all
1016
- * matching features. In datasets containing features with duplicate geometries,
1017
- * feature IDs may be duplicated (IDs are a hash of geometry) and so more
1018
- * results may be returned than IDs in the request.
1019
- * @internal
1020
- * @experimental
1021
- */
1022
1127
  getFeatures(options) {
1023
1128
  try {
1024
1129
  const _this2 = this;
1025
1130
  const {
1026
1131
  filterOwner,
1027
1132
  spatialFilter,
1133
+ spatialFiltersMode,
1134
+ spatialIndexReferenceViewState,
1028
1135
  abortController,
1029
1136
  ...params
1030
1137
  } = options;
@@ -1036,10 +1143,14 @@ class WidgetBaseSource {
1036
1143
  limit,
1037
1144
  tileResolution
1038
1145
  } = params;
1146
+ const source = _this2.getModelSource(filterOwner);
1147
+ const spatialFiltersResolution = _this2._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
1039
1148
  return Promise.resolve(executeModel({
1040
1149
  model: 'pick',
1041
1150
  source: {
1042
- ..._this2.getModelSource(filterOwner),
1151
+ ...source,
1152
+ spatialFiltersResolution,
1153
+ spatialFiltersMode,
1043
1154
  spatialFilter
1044
1155
  },
1045
1156
  params: {
@@ -1066,19 +1177,14 @@ class WidgetBaseSource {
1066
1177
  return Promise.reject(e);
1067
1178
  }
1068
1179
  }
1069
- /****************************************************************************
1070
- * FORMULA
1071
- */
1072
- /**
1073
- * Returns a scalar numerical statistic over all matching data. Suitable
1074
- * for 'headline' or 'scorecard' figures such as counts and sums.
1075
- */
1076
1180
  getFormula(options) {
1077
1181
  try {
1078
1182
  const _this3 = this;
1079
1183
  const {
1080
1184
  filterOwner,
1081
1185
  spatialFilter,
1186
+ spatialFiltersMode,
1187
+ spatialIndexReferenceViewState,
1082
1188
  abortController,
1083
1189
  operationExp,
1084
1190
  ...params
@@ -1087,15 +1193,19 @@ class WidgetBaseSource {
1087
1193
  column,
1088
1194
  operation
1089
1195
  } = params;
1196
+ const source = _this3.getModelSource(filterOwner);
1197
+ const spatialFiltersResolution = _this3._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
1090
1198
  return Promise.resolve(executeModel({
1091
1199
  model: 'formula',
1092
1200
  source: {
1093
- ..._this3.getModelSource(filterOwner),
1201
+ ...source,
1202
+ spatialFiltersResolution,
1203
+ spatialFiltersMode,
1094
1204
  spatialFilter
1095
1205
  },
1096
1206
  params: {
1097
1207
  column: column ?? '*',
1098
- operation,
1208
+ operation: operation ?? 'count',
1099
1209
  operationExp
1100
1210
  },
1101
1211
  opts: {
@@ -1106,19 +1216,14 @@ class WidgetBaseSource {
1106
1216
  return Promise.reject(e);
1107
1217
  }
1108
1218
  }
1109
- /****************************************************************************
1110
- * HISTOGRAM
1111
- */
1112
- /**
1113
- * Returns a list of labeled datapoints for 'bins' of data defined as ticks
1114
- * over a numerical range. Suitable for histogram charts.
1115
- */
1116
1219
  getHistogram(options) {
1117
1220
  try {
1118
1221
  const _this4 = this;
1119
1222
  const {
1120
1223
  filterOwner,
1121
1224
  spatialFilter,
1225
+ spatialFiltersMode,
1226
+ spatialIndexReferenceViewState,
1122
1227
  abortController,
1123
1228
  ...params
1124
1229
  } = options;
@@ -1127,10 +1232,14 @@ class WidgetBaseSource {
1127
1232
  operation,
1128
1233
  ticks
1129
1234
  } = params;
1235
+ const source = _this4.getModelSource(filterOwner);
1236
+ const spatialFiltersResolution = _this4._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
1130
1237
  return Promise.resolve(executeModel({
1131
1238
  model: 'histogram',
1132
1239
  source: {
1133
- ..._this4.getModelSource(filterOwner),
1240
+ ...source,
1241
+ spatialFiltersResolution,
1242
+ spatialFiltersMode,
1134
1243
  spatialFilter
1135
1244
  },
1136
1245
  params: {
@@ -1161,30 +1270,28 @@ class WidgetBaseSource {
1161
1270
  return Promise.reject(e);
1162
1271
  }
1163
1272
  }
1164
- /****************************************************************************
1165
- * RANGE
1166
- */
1167
- /**
1168
- * Returns a range (min and max) for a numerical column of matching rows.
1169
- * Suitable for displaying certain 'headline' or 'scorecard' statistics,
1170
- * or rendering a range slider UI for filtering.
1171
- */
1172
1273
  getRange(options) {
1173
1274
  try {
1174
1275
  const _this5 = this;
1175
1276
  const {
1176
1277
  filterOwner,
1177
1278
  spatialFilter,
1279
+ spatialFiltersMode,
1280
+ spatialIndexReferenceViewState,
1178
1281
  abortController,
1179
1282
  ...params
1180
1283
  } = options;
1181
1284
  const {
1182
1285
  column
1183
1286
  } = params;
1287
+ const source = _this5.getModelSource(filterOwner);
1288
+ const spatialFiltersResolution = _this5._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
1184
1289
  return Promise.resolve(executeModel({
1185
1290
  model: 'range',
1186
1291
  source: {
1187
- ..._this5.getModelSource(filterOwner),
1292
+ ...source,
1293
+ spatialFiltersResolution,
1294
+ spatialFiltersMode,
1188
1295
  spatialFilter
1189
1296
  },
1190
1297
  params: {
@@ -1198,19 +1305,14 @@ class WidgetBaseSource {
1198
1305
  return Promise.reject(e);
1199
1306
  }
1200
1307
  }
1201
- /****************************************************************************
1202
- * SCATTER
1203
- */
1204
- /**
1205
- * Returns a list of bivariate datapoints defined as numerical 'x' and 'y'
1206
- * values. Suitable for rendering scatter plots.
1207
- */
1208
1308
  getScatter(options) {
1209
1309
  try {
1210
1310
  const _this6 = this;
1211
1311
  const {
1212
1312
  filterOwner,
1213
1313
  spatialFilter,
1314
+ spatialFiltersMode,
1315
+ spatialIndexReferenceViewState,
1214
1316
  abortController,
1215
1317
  ...params
1216
1318
  } = options;
@@ -1220,12 +1322,16 @@ class WidgetBaseSource {
1220
1322
  yAxisColumn,
1221
1323
  yAxisJoinOperation
1222
1324
  } = params;
1325
+ const source = _this6.getModelSource(filterOwner);
1326
+ const spatialFiltersResolution = _this6._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
1223
1327
  // Make sure this is sync with the same constant in cloud-native/maps-api
1224
1328
  const HARD_LIMIT = 500;
1225
1329
  return Promise.resolve(executeModel({
1226
1330
  model: 'scatterplot',
1227
1331
  source: {
1228
- ..._this6.getModelSource(filterOwner),
1332
+ ...source,
1333
+ spatialFiltersResolution,
1334
+ spatialFiltersMode,
1229
1335
  spatialFilter
1230
1336
  },
1231
1337
  params: {
@@ -1249,19 +1355,14 @@ class WidgetBaseSource {
1249
1355
  return Promise.reject(e);
1250
1356
  }
1251
1357
  }
1252
- /****************************************************************************
1253
- * TABLE
1254
- */
1255
- /**
1256
- * Returns a list of arbitrary data rows, with support for pagination and
1257
- * sorting. Suitable for displaying tables and lists.
1258
- */
1259
1358
  getTable(options) {
1260
1359
  try {
1261
1360
  const _this7 = this;
1262
1361
  const {
1263
1362
  filterOwner,
1264
1363
  spatialFilter,
1364
+ spatialFiltersMode,
1365
+ spatialIndexReferenceViewState,
1265
1366
  abortController,
1266
1367
  ...params
1267
1368
  } = options;
@@ -1272,10 +1373,14 @@ class WidgetBaseSource {
1272
1373
  offset = 0,
1273
1374
  limit = 10
1274
1375
  } = params;
1376
+ const source = _this7.getModelSource(filterOwner);
1377
+ const spatialFiltersResolution = _this7._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
1275
1378
  return Promise.resolve(executeModel({
1276
1379
  model: 'table',
1277
1380
  source: {
1278
- ..._this7.getModelSource(filterOwner),
1381
+ ...source,
1382
+ spatialFiltersResolution,
1383
+ spatialFiltersMode,
1279
1384
  spatialFilter
1280
1385
  },
1281
1386
  params: {
@@ -1297,13 +1402,6 @@ class WidgetBaseSource {
1297
1402
  return Promise.reject(e);
1298
1403
  }
1299
1404
  }
1300
- /****************************************************************************
1301
- * TIME SERIES
1302
- */
1303
- /**
1304
- * Returns a series of labeled numerical values, grouped into equally-sized
1305
- * time intervals. Suitable for rendering time series charts.
1306
- */
1307
1405
  getTimeSeries(options) {
1308
1406
  try {
1309
1407
  const _this8 = this;
@@ -1311,6 +1409,8 @@ class WidgetBaseSource {
1311
1409
  filterOwner,
1312
1410
  abortController,
1313
1411
  spatialFilter,
1412
+ spatialFiltersMode,
1413
+ spatialIndexReferenceViewState,
1314
1414
  ...params
1315
1415
  } = options;
1316
1416
  const {
@@ -1324,10 +1424,14 @@ class WidgetBaseSource {
1324
1424
  splitByCategoryLimit,
1325
1425
  splitByCategoryValues
1326
1426
  } = params;
1427
+ const source = _this8.getModelSource(filterOwner);
1428
+ const spatialFiltersResolution = _this8._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
1327
1429
  return Promise.resolve(executeModel({
1328
1430
  model: 'timeseries',
1329
1431
  source: {
1330
- ..._this8.getModelSource(filterOwner),
1432
+ ...source,
1433
+ spatialFiltersResolution,
1434
+ spatialFiltersMode,
1331
1435
  spatialFilter
1332
1436
  },
1333
1437
  params: {
@@ -1353,14 +1457,6 @@ class WidgetBaseSource {
1353
1457
  }
1354
1458
  }
1355
1459
  }
1356
- WidgetBaseSource.defaultProps = {
1357
- apiVersion: exports.ApiVersion.V3,
1358
- apiBaseUrl: DEFAULT_API_BASE_URL,
1359
- clientId: getClient(),
1360
- filters: {},
1361
- filtersLogicalOperator: 'and',
1362
- geoColumn: DEFAULT_GEO_COLUMN
1363
- };
1364
1460
 
1365
1461
  /**
1366
1462
  * Source for Widget API requests on a data source defined by a SQL query.
@@ -1384,7 +1480,7 @@ WidgetBaseSource.defaultProps = {
1384
1480
  * const { widgetSource } = await data;
1385
1481
  * ```
1386
1482
  */
1387
- class WidgetQuerySource extends WidgetBaseSource {
1483
+ class WidgetQuerySource extends WidgetRemoteSource {
1388
1484
  getModelSource(owner) {
1389
1485
  return {
1390
1486
  ...super._getModelSource(owner),
@@ -1417,7 +1513,7 @@ class WidgetQuerySource extends WidgetBaseSource {
1417
1513
  * const { widgetSource } = await data;
1418
1514
  * ```
1419
1515
  */
1420
- class WidgetTableSource extends WidgetBaseSource {
1516
+ class WidgetTableSource extends WidgetRemoteSource {
1421
1517
  getModelSource(owner) {
1422
1518
  return {
1423
1519
  ...super._getModelSource(owner),
@@ -1427,150 +1523,2119 @@ class WidgetTableSource extends WidgetBaseSource {
1427
1523
  }
1428
1524
  }
1429
1525
 
1430
- // deck.gl
1431
- const h3QuerySource = function (options) {
1432
- try {
1433
- const {
1434
- aggregationExp,
1435
- aggregationResLevel = DEFAULT_AGGREGATION_RES_LEVEL_H3,
1436
- sqlQuery,
1437
- spatialDataColumn = 'h3',
1438
- queryParameters,
1439
- filters
1440
- } = options;
1441
- const urlParameters = {
1442
- aggregationExp,
1443
- spatialDataColumn,
1444
- spatialDataType: 'h3',
1445
- q: sqlQuery
1446
- };
1447
- if (aggregationResLevel) {
1448
- urlParameters.aggregationResLevel = String(aggregationResLevel);
1449
- }
1450
- if (queryParameters) {
1451
- urlParameters.queryParameters = queryParameters;
1526
+ function makeIntervalComplete(intervals) {
1527
+ return intervals.map(val => {
1528
+ if (val[0] === undefined || val[0] === null) {
1529
+ return [Number.MIN_SAFE_INTEGER, val[1]];
1452
1530
  }
1453
- if (filters) {
1454
- urlParameters.filters = filters;
1531
+ if (val[1] === undefined || val[1] === null) {
1532
+ return [val[0], Number.MAX_SAFE_INTEGER];
1455
1533
  }
1456
- return Promise.resolve(baseSource('query', options, urlParameters).then(result => ({
1457
- ...result,
1458
- widgetSource: new WidgetQuerySource(options)
1459
- })));
1460
- } catch (e) {
1461
- return Promise.reject(e);
1462
- }
1534
+ return val;
1535
+ });
1536
+ }
1537
+
1538
+ const filterFunctions = {
1539
+ [exports.FilterType.IN]: filterIn,
1540
+ [exports.FilterType.BETWEEN]: filterBetween,
1541
+ [exports.FilterType.TIME]: filterTime,
1542
+ [exports.FilterType.CLOSED_OPEN]: filterClosedOpen,
1543
+ [exports.FilterType.STRING_SEARCH]: filterStringSearch
1463
1544
  };
1545
+ function filterIn(filterValues, featureValue) {
1546
+ return filterValues.includes(featureValue);
1547
+ }
1548
+ // FilterTypes.BETWEEN
1549
+ function filterBetween(filterValues, featureValue) {
1550
+ const checkRange = range => {
1551
+ const [lowerBound, upperBound] = range;
1552
+ return featureValue >= lowerBound && featureValue <= upperBound;
1553
+ };
1554
+ return makeIntervalComplete(filterValues).some(checkRange);
1555
+ }
1556
+ function filterTime(filterValues, featureValue) {
1557
+ const featureValueAsTimestamp = new Date(featureValue).getTime();
1558
+ if (isFinite(featureValueAsTimestamp)) {
1559
+ return filterBetween(filterValues, featureValueAsTimestamp);
1560
+ } else {
1561
+ throw new Error(`Column used to filter by time isn't well formatted.`);
1562
+ }
1563
+ }
1564
+ // FilterTypes.CLOSED_OPEN
1565
+ function filterClosedOpen(filterValues, featureValue) {
1566
+ const checkRange = range => {
1567
+ const [lowerBound, upperBound] = range;
1568
+ return featureValue >= lowerBound && featureValue < upperBound;
1569
+ };
1570
+ return makeIntervalComplete(filterValues).some(checkRange);
1571
+ }
1572
+ // FilterTypes.STRING_SEARCH
1573
+ function filterStringSearch(filterValues, featureValue, params) {
1574
+ if (params === void 0) {
1575
+ params = {};
1576
+ }
1577
+ const normalizedFeatureValue = normalize(featureValue, params);
1578
+ const stringRegExp = params.useRegExp ? filterValues : filterValues.map(filterValue => {
1579
+ let stringRegExp = escapeRegExp(normalize(filterValue, params));
1580
+ if (params.mustStart) stringRegExp = `^${stringRegExp}`;
1581
+ if (params.mustEnd) stringRegExp = `${stringRegExp}$`;
1582
+ return stringRegExp;
1583
+ });
1584
+ const regex = new RegExp(stringRegExp.join('|'), params.caseSensitive ? 'g' : 'gi');
1585
+ return !!normalizedFeatureValue.match(regex);
1586
+ }
1587
+ // Aux
1588
+ const specialCharRegExp = /[.*+?^${}()|[\]\\]/g;
1589
+ const normalizeRegExp = /\p{Diacritic}/gu;
1590
+ function escapeRegExp(value) {
1591
+ return value.replace(specialCharRegExp, '\\$&');
1592
+ }
1593
+ function normalize(data, params) {
1594
+ let normalizedData = String(data);
1595
+ if (!params.keepSpecialCharacters) normalizedData = normalizedData.normalize('NFD').replace(normalizeRegExp, '');
1596
+ return normalizedData;
1597
+ }
1464
1598
 
1465
- // deck.gl
1466
- const h3TableSource = function (options) {
1467
- try {
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'
1480
- };
1481
- if (aggregationResLevel) {
1482
- urlParameters.aggregationResLevel = String(aggregationResLevel);
1483
- }
1484
- if (filters) {
1485
- urlParameters.filters = filters;
1599
+ const LOGICAL_OPERATOR_METHODS = {
1600
+ and: 'every',
1601
+ or: 'some'
1602
+ };
1603
+ function passesFilter(columns, filters, feature, filtersLogicalOperator) {
1604
+ const method = LOGICAL_OPERATOR_METHODS[filtersLogicalOperator];
1605
+ return columns[method](column => {
1606
+ const columnFilters = filters[column];
1607
+ const columnFilterTypes = Object.keys(columnFilters);
1608
+ if (!feature || feature[column] === null || feature[column] === undefined) {
1609
+ return false;
1486
1610
  }
1487
- return Promise.resolve(baseSource('table', options, urlParameters).then(result => ({
1488
- ...result,
1489
- widgetSource: new WidgetTableSource(options)
1490
- })));
1491
- } catch (e) {
1492
- return Promise.reject(e);
1611
+ return columnFilterTypes.every(filter => {
1612
+ const filterFunction = filterFunctions[filter];
1613
+ if (!filterFunction) {
1614
+ throw new Error(`"${filter}" filter is not implemented.`);
1615
+ }
1616
+ return filterFunction(columnFilters[filter].values, feature[column], columnFilters[filter].params);
1617
+ });
1618
+ });
1619
+ }
1620
+ function buildFeatureFilter(_ref) {
1621
+ let {
1622
+ filters = {},
1623
+ type = 'boolean',
1624
+ filtersLogicalOperator = 'and'
1625
+ } = _ref;
1626
+ const columns = Object.keys(filters);
1627
+ if (!columns.length) {
1628
+ return () => type === 'number' ? 1 : true;
1493
1629
  }
1494
- };
1495
-
1496
- // deck.gl
1497
- const h3TilesetSource = function (options) {
1498
- try {
1499
- const {
1500
- tableName
1501
- } = options;
1502
- const urlParameters = {
1503
- name: tableName
1504
- };
1505
- return Promise.resolve(baseSource('tileset', options, urlParameters));
1506
- } catch (e) {
1507
- return Promise.reject(e);
1630
+ return feature => {
1631
+ const f = feature.properties || feature;
1632
+ const featurePassesFilter = passesFilter(columns, filters, f, filtersLogicalOperator);
1633
+ return type === 'number' ? Number(featurePassesFilter) : featurePassesFilter;
1634
+ };
1635
+ }
1636
+ // Apply certain filters to a collection of features
1637
+ function applyFilters(features, filters, filtersLogicalOperator) {
1638
+ return Object.keys(filters).length ? features.filter(buildFeatureFilter({
1639
+ filters,
1640
+ filtersLogicalOperator
1641
+ })) : features;
1642
+ }
1643
+ // Binary
1644
+ function buildBinaryFeatureFilter(_ref2) {
1645
+ let {
1646
+ filters = {}
1647
+ } = _ref2;
1648
+ const columns = Object.keys(filters);
1649
+ if (!columns.length) {
1650
+ return () => 1;
1508
1651
  }
1652
+ return (featureIdIdx, binaryData) => passesFilterUsingBinary(columns, filters, featureIdIdx, binaryData);
1653
+ }
1654
+ function getValueFromNumericProps(featureIdIdx, binaryData, _ref3) {
1655
+ let {
1656
+ column
1657
+ } = _ref3;
1658
+ return binaryData.numericProps?.[column]?.value[featureIdIdx];
1659
+ }
1660
+ function getValueFromProperties(featureIdIdx, binaryData, _ref4) {
1661
+ let {
1662
+ column
1663
+ } = _ref4;
1664
+ const propertyIdx = binaryData.featureIds.value[featureIdIdx];
1665
+ return binaryData.properties[propertyIdx]?.[column];
1666
+ }
1667
+ const GET_VALUE_BY_BINARY_PROP = {
1668
+ properties: getValueFromProperties,
1669
+ numericProps: getValueFromNumericProps
1509
1670
  };
1671
+ function getBinaryPropertyByFilterValues(filterValues) {
1672
+ return typeof filterValues.flat()[0] === 'string' ? 'properties' : 'numericProps';
1673
+ }
1674
+ function getFeatureValue(featureIdIdx, binaryData, filter) {
1675
+ const {
1676
+ column,
1677
+ values
1678
+ } = filter;
1679
+ const binaryProp = getBinaryPropertyByFilterValues(values);
1680
+ const getFeatureValueFn = GET_VALUE_BY_BINARY_PROP[binaryProp];
1681
+ return getFeatureValueFn(featureIdIdx, binaryData, {
1682
+ column
1683
+ });
1684
+ }
1685
+ function passesFilterUsingBinary(columns, filters, featureIdIdx, binaryData) {
1686
+ return columns.every(column => {
1687
+ const columnFilters = filters[column];
1688
+ return Object.entries(columnFilters).every(_ref5 => {
1689
+ let [type, {
1690
+ values
1691
+ }] = _ref5;
1692
+ const filterFn = filterFunctions[type];
1693
+ if (!filterFn) {
1694
+ throw new Error(`"${type}" filter is not implemented.`);
1695
+ }
1696
+ if (!values) return 0;
1697
+ const featureValue = getFeatureValue(featureIdIdx, binaryData, {
1698
+ type: type,
1699
+ column,
1700
+ values
1701
+ });
1702
+ if (featureValue === undefined || featureValue === null) return 0;
1703
+ return filterFn(values, featureValue);
1704
+ });
1705
+ });
1706
+ }
1510
1707
 
1511
- // deck.gl
1512
- const rasterSource = function (options) {
1513
- try {
1514
- const {
1515
- tableName,
1516
- filters
1517
- } = options;
1518
- const urlParameters = {
1519
- name: tableName
1520
- };
1521
- if (filters) {
1522
- urlParameters.filters = filters;
1708
+ function geojsonFeatures(_ref) {
1709
+ let {
1710
+ geojson,
1711
+ spatialFilter,
1712
+ uniqueIdProperty
1713
+ } = _ref;
1714
+ let uniqueIdx = 0;
1715
+ const map = new Map();
1716
+ if (!spatialFilter) {
1717
+ return [];
1718
+ }
1719
+ for (const feature of geojson.features) {
1720
+ const uniqueId = uniqueIdProperty ? feature.properties[uniqueIdProperty] : ++uniqueIdx;
1721
+ if (!map.has(uniqueId) && intersects(spatialFilter, feature)) {
1722
+ map.set(uniqueId, feature.properties);
1523
1723
  }
1524
- return Promise.resolve(baseSource('raster', options, urlParameters));
1525
- } catch (e) {
1526
- return Promise.reject(e);
1527
1724
  }
1528
- };
1725
+ return Array.from(map.values());
1726
+ }
1529
1727
 
1530
- // deck.gl
1531
- const quadbinQuerySource = function (options) {
1532
- try {
1533
- const {
1534
- aggregationExp,
1535
- aggregationResLevel = DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN,
1536
- sqlQuery,
1537
- spatialDataColumn = 'quadbin',
1538
- queryParameters,
1539
- filters
1540
- } = options;
1541
- const urlParameters = {
1542
- aggregationExp,
1543
- q: sqlQuery,
1544
- spatialDataColumn,
1545
- spatialDataType: 'quadbin'
1546
- };
1547
- if (aggregationResLevel) {
1548
- urlParameters.aggregationResLevel = String(aggregationResLevel);
1549
- }
1550
- if (queryParameters) {
1551
- urlParameters.queryParameters = queryParameters;
1552
- }
1553
- if (filters) {
1554
- urlParameters.filters = filters;
1555
- }
1556
- return Promise.resolve(baseSource('query', options, urlParameters).then(result => ({
1557
- ...result,
1558
- widgetSource: new WidgetQuerySource(options)
1559
- })));
1560
- } catch (e) {
1561
- return Promise.reject(e);
1728
+ // math.gl
1729
+ // SPDX-License-Identifier: MIT
1730
+ // Copyright (c) vis.gl contributors
1731
+ const DEFAULT_CONFIG = {
1732
+ EPSILON: 1e-12,
1733
+ debug: false,
1734
+ precision: 4,
1735
+ printTypes: false,
1736
+ printDegrees: false,
1737
+ printRowMajor: true,
1738
+ _cartographicRadians: false
1739
+ };
1740
+ // Configuration is truly global as of v3.6 to ensure single config even if multiple copies of math.gl
1741
+ // Multiple copies of config can be quite tricky to debug...
1742
+ globalThis.mathgl = globalThis.mathgl || {
1743
+ config: {
1744
+ ...DEFAULT_CONFIG
1562
1745
  }
1563
1746
  };
1747
+ /**
1748
+ * Check if value is an "array"
1749
+ * Returns `true` if value is either an array or a typed array
1750
+ * Note: returns `false` for `ArrayBuffer` and `DataView` instances
1751
+ * @note isTypedArray and isNumericArray are often more useful in TypeScript
1752
+ */
1753
+ function isArray(value) {
1754
+ return Array.isArray(value) || ArrayBuffer.isView(value) && !(value instanceof DataView);
1755
+ }
1756
+ function lerp(a, b, t) {
1757
+ if (isArray(a)) {
1758
+ return a.map((ai, i) => lerp(ai, b[i], t));
1759
+ }
1760
+ return t * b + (1 - t) * a;
1761
+ }
1564
1762
 
1565
- // deck.gl
1566
- const quadbinTableSource = function (options) {
1567
- try {
1568
- const {
1569
- aggregationExp,
1570
- aggregationResLevel = DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN,
1571
- spatialDataColumn = 'quadbin',
1572
- tableName,
1573
- filters
1763
+ // Replacement for the external assert method to reduce bundle size
1764
+ // Note: We don't use the second "message" argument in calling code,
1765
+ // so no need to support it here
1766
+ function assert(condition, message) {
1767
+ if (!condition) {
1768
+ throw new Error(message || '@math.gl/web-mercator: assertion failed.');
1769
+ }
1770
+ }
1771
+
1772
+ // TODO - THE UTILITIES IN THIS FILE SHOULD BE IMPORTED FROM WEB-MERCATOR-VIEWPORT MODULE
1773
+ // CONSTANTS
1774
+ const PI = Math.PI;
1775
+ const PI_4 = PI / 4;
1776
+ const DEGREES_TO_RADIANS = PI / 180;
1777
+ const RADIANS_TO_DEGREES = 180 / PI;
1778
+ const TILE_SIZE = 512;
1779
+ /**
1780
+ * Project [lng,lat] on sphere onto [x,y] on 512*512 Mercator Zoom 0 tile.
1781
+ * Performs the nonlinear part of the web mercator projection.
1782
+ * Remaining projection is done with 4x4 matrices which also handles
1783
+ * perspective.
1784
+ *
1785
+ * @param lngLat - [lng, lat] coordinates
1786
+ * Specifies a point on the sphere to project onto the map.
1787
+ * @return [x,y] coordinates.
1788
+ */
1789
+ function lngLatToWorld(lngLat) {
1790
+ const [lng, lat] = lngLat;
1791
+ assert(Number.isFinite(lng));
1792
+ assert(Number.isFinite(lat) && lat >= -90 && lat <= 90, 'invalid latitude');
1793
+ const lambda2 = lng * DEGREES_TO_RADIANS;
1794
+ const phi2 = lat * DEGREES_TO_RADIANS;
1795
+ const x = TILE_SIZE * (lambda2 + PI) / (2 * PI);
1796
+ const y = TILE_SIZE * (PI + Math.log(Math.tan(PI_4 + phi2 * 0.5))) / (2 * PI);
1797
+ return [x, y];
1798
+ }
1799
+ /**
1800
+ * Unproject world point [x,y] on map onto {lat, lon} on sphere
1801
+ *
1802
+ * @param xy - array with [x,y] members
1803
+ * representing point on projected map plane
1804
+ * @return - array with [x,y] of point on sphere.
1805
+ * Has toArray method if you need a GeoJSON Array.
1806
+ * Per cartographic tradition, lat and lon are specified as degrees.
1807
+ */
1808
+ function worldToLngLat(xy) {
1809
+ const [x, y] = xy;
1810
+ const lambda2 = x / TILE_SIZE * (2 * PI) - PI;
1811
+ const phi2 = 2 * (Math.atan(Math.exp(y / TILE_SIZE * (2 * PI) - PI)) - PI_4);
1812
+ return [lambda2 * RADIANS_TO_DEGREES, phi2 * RADIANS_TO_DEGREES];
1813
+ }
1814
+
1815
+ const TRANSFORM_FN$1 = {
1816
+ Point: transformPoint$1,
1817
+ MultiPoint: transformMultiPoint$1,
1818
+ LineString: transformLineString$1,
1819
+ MultiLineString: transformMultiLineString$1,
1820
+ Polygon: transformPolygon$1,
1821
+ MultiPolygon: transformMultiPolygon$1
1822
+ };
1823
+ /**
1824
+ * Transform WGS84 coordinates to tile coords.
1825
+ * 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)
1826
+ *
1827
+ * @param geometry - any valid geojson geometry
1828
+ * @param bbox - geojson bbox
1829
+ */
1830
+ function transformToTileCoords(geometry, bbox) {
1831
+ const [west, south, east, north] = bbox;
1832
+ const nw = projectFlat([west, north]);
1833
+ const se = projectFlat([east, south]);
1834
+ const projectedBbox = [nw, se];
1835
+ if (geometry.type === 'GeometryCollection') {
1836
+ throw new Error('Unsupported geometry type GeometryCollection');
1837
+ }
1838
+ const transformFn = TRANSFORM_FN$1[geometry.type];
1839
+ const coordinates = transformFn(geometry.coordinates, projectedBbox);
1840
+ return {
1841
+ ...geometry,
1842
+ coordinates
1843
+ };
1844
+ }
1845
+ function transformPoint$1(_ref, _ref2) {
1846
+ let [pointX, pointY] = _ref;
1847
+ let [nw, se] = _ref2;
1848
+ const x = inverseLerp(nw[0], se[0], pointX);
1849
+ const y = inverseLerp(nw[1], se[1], pointY);
1850
+ return [x, y];
1851
+ }
1852
+ function getPoints$1(geometry, bbox) {
1853
+ return geometry.map(g => transformPoint$1(projectFlat(g), bbox));
1854
+ }
1855
+ function transformMultiPoint$1(multiPoint, bbox) {
1856
+ return getPoints$1(multiPoint, bbox);
1857
+ }
1858
+ function transformLineString$1(line, bbox) {
1859
+ return getPoints$1(line, bbox);
1860
+ }
1861
+ function transformMultiLineString$1(multiLineString, bbox) {
1862
+ return multiLineString.map(lineString => transformLineString$1(lineString, bbox));
1863
+ }
1864
+ function transformPolygon$1(polygon, bbox) {
1865
+ return polygon.map(polygonRing => getPoints$1(polygonRing, bbox));
1866
+ }
1867
+ function transformMultiPolygon$1(multiPolygon, bbox) {
1868
+ return multiPolygon.map(polygon => transformPolygon$1(polygon, bbox));
1869
+ }
1870
+ function projectFlat(xyz) {
1871
+ return lngLatToWorld(xyz);
1872
+ }
1873
+ function inverseLerp(a, b, x) {
1874
+ return (x - a) / (b - a);
1875
+ }
1876
+
1877
+ const TRANSFORM_FN = {
1878
+ Point: transformPoint,
1879
+ MultiPoint: transformMultiPoint,
1880
+ LineString: transformLineString,
1881
+ MultiLineString: transformMultiLineString,
1882
+ Polygon: transformPolygon,
1883
+ MultiPolygon: transformMultiPolygon
1884
+ };
1885
+ /**
1886
+ * Transform tile coords to WGS84 coordinates.
1887
+ *
1888
+ * @param geometry - any valid geojson geometry
1889
+ * @param bbox - geojson bbox
1890
+ */
1891
+ function transformTileCoordsToWGS84(geometry, bbox) {
1892
+ const [west, south, east, north] = bbox;
1893
+ const nw = lngLatToWorld([west, north]);
1894
+ const se = lngLatToWorld([east, south]);
1895
+ const projectedBbox = [nw, se];
1896
+ if (geometry.type === 'GeometryCollection') {
1897
+ throw new Error('Unsupported geometry type GeometryCollection');
1898
+ }
1899
+ const transformFn = TRANSFORM_FN[geometry.type];
1900
+ const coordinates = transformFn(geometry.coordinates, projectedBbox);
1901
+ return {
1902
+ ...geometry,
1903
+ coordinates
1904
+ };
1905
+ }
1906
+ function transformPoint(_ref, _ref2) {
1907
+ let [pointX, pointY] = _ref;
1908
+ let [nw, se] = _ref2;
1909
+ const x = lerp(nw[0], se[0], pointX);
1910
+ const y = lerp(nw[1], se[1], pointY);
1911
+ return worldToLngLat([x, y]);
1912
+ }
1913
+ function getPoints(geometry, bbox) {
1914
+ return geometry.map(g => transformPoint(g, bbox));
1915
+ }
1916
+ function transformMultiPoint(multiPoint, bbox) {
1917
+ return getPoints(multiPoint, bbox);
1918
+ }
1919
+ function transformLineString(line, bbox) {
1920
+ return getPoints(line, bbox);
1921
+ }
1922
+ function transformMultiLineString(multiLineString, bbox) {
1923
+ return multiLineString.map(lineString => transformLineString(lineString, bbox));
1924
+ }
1925
+ function transformPolygon(polygon, bbox) {
1926
+ return polygon.map(polygonRing => getPoints(polygonRing, bbox));
1927
+ }
1928
+ function transformMultiPolygon(multiPolygon, bbox) {
1929
+ return multiPolygon.map(polygon => transformPolygon(polygon, bbox));
1930
+ }
1931
+
1932
+ const FEATURE_GEOM_PROPERTY = '__geomValue';
1933
+ function tileFeaturesGeometries(_ref) {
1934
+ let {
1935
+ tiles,
1936
+ tileFormat,
1937
+ spatialFilter,
1938
+ uniqueIdProperty,
1939
+ options
1940
+ } = _ref;
1941
+ const map = new Map();
1942
+ for (const tile of tiles) {
1943
+ // Discard if it's not a visible tile (only check false value, not undefined)
1944
+ // or tile has not data
1945
+ if (tile.isVisible === false || !tile.data) {
1946
+ continue;
1947
+ }
1948
+ const bbox = [tile.bbox.west, tile.bbox.south, tile.bbox.east, tile.bbox.north];
1949
+ const bboxToGeom = bboxPolygon(bbox);
1950
+ const tileIsFullyVisible = booleanWithin(bboxToGeom, spatialFilter);
1951
+ // Clip the geometry to intersect with the tile
1952
+ const spatialFilterFeature = {
1953
+ type: 'Feature',
1954
+ geometry: spatialFilter,
1955
+ properties: {}
1956
+ };
1957
+ const clippedGeometryToIntersect = intersect(helpers.featureCollection([bboxToGeom, spatialFilterFeature]));
1958
+ if (!clippedGeometryToIntersect) {
1959
+ continue;
1960
+ }
1961
+ // We assume that MVT tileFormat uses local coordinates so we transform the geometry to intersect to tile coordinates [0..1],
1962
+ // while in the case of 'geojson' or binary, the geometries are already in WGS84
1963
+ const transformedGeometryToIntersect = tileFormat === exports.TileFormat.MVT ? transformToTileCoords(clippedGeometryToIntersect.geometry, bbox) : clippedGeometryToIntersect.geometry;
1964
+ createIndicesForPoints(tile.data.points);
1965
+ calculateFeatures({
1966
+ map,
1967
+ tileIsFullyVisible,
1968
+ geometryIntersection: transformedGeometryToIntersect,
1969
+ data: tile.data.points,
1970
+ type: 'Point',
1971
+ bbox,
1972
+ tileFormat,
1973
+ uniqueIdProperty,
1974
+ options
1975
+ });
1976
+ calculateFeatures({
1977
+ map,
1978
+ tileIsFullyVisible,
1979
+ geometryIntersection: transformedGeometryToIntersect,
1980
+ data: tile.data.lines,
1981
+ type: 'LineString',
1982
+ bbox,
1983
+ tileFormat,
1984
+ uniqueIdProperty,
1985
+ options
1986
+ });
1987
+ calculateFeatures({
1988
+ map,
1989
+ tileIsFullyVisible,
1990
+ geometryIntersection: transformedGeometryToIntersect,
1991
+ data: tile.data.polygons,
1992
+ type: 'Polygon',
1993
+ bbox,
1994
+ tileFormat,
1995
+ uniqueIdProperty,
1996
+ options
1997
+ });
1998
+ }
1999
+ return Array.from(map.values());
2000
+ }
2001
+ function processTileFeatureProperties(_ref2) {
2002
+ let {
2003
+ map,
2004
+ data,
2005
+ startIndex,
2006
+ endIndex,
2007
+ type,
2008
+ bbox,
2009
+ tileFormat,
2010
+ uniqueIdProperty,
2011
+ storeGeometry,
2012
+ geometryIntersection
2013
+ } = _ref2;
2014
+ const tileProps = getPropertiesFromTile(data, startIndex);
2015
+ const uniquePropertyValue = getUniquePropertyValue(tileProps, uniqueIdProperty, map);
2016
+ if (!uniquePropertyValue || map.has(uniquePropertyValue)) {
2017
+ return;
2018
+ }
2019
+ let geometry = null;
2020
+ // Only calculate geometry if necessary
2021
+ if (storeGeometry || geometryIntersection) {
2022
+ const {
2023
+ positions
2024
+ } = data;
2025
+ const ringCoordinates = getRingCoordinatesFor(startIndex, endIndex, positions);
2026
+ geometry = getFeatureByType(ringCoordinates, type);
2027
+ }
2028
+ // If intersection is required, check before proceeding
2029
+ if (geometry && geometryIntersection && !intersects(geometry, geometryIntersection)) {
2030
+ return;
2031
+ }
2032
+ const properties = parseProperties(tileProps);
2033
+ // Only save geometry if necessary
2034
+ if (storeGeometry && geometry) {
2035
+ properties[FEATURE_GEOM_PROPERTY] = tileFormat === exports.TileFormat.MVT ? transformTileCoordsToWGS84(geometry, bbox) : geometry;
2036
+ }
2037
+ map.set(uniquePropertyValue, properties);
2038
+ }
2039
+ function addIntersectedFeaturesInTile(_ref3) {
2040
+ let {
2041
+ map,
2042
+ data,
2043
+ geometryIntersection,
2044
+ type,
2045
+ bbox,
2046
+ tileFormat,
2047
+ uniqueIdProperty,
2048
+ options
2049
+ } = _ref3;
2050
+ const indices = getIndices(data);
2051
+ const storeGeometry = options?.storeGeometry || false;
2052
+ for (let i = 0; i < indices.length - 1; i++) {
2053
+ const startIndex = indices[i];
2054
+ const endIndex = indices[i + 1];
2055
+ processTileFeatureProperties({
2056
+ map,
2057
+ data,
2058
+ startIndex,
2059
+ endIndex,
2060
+ type,
2061
+ bbox,
2062
+ tileFormat,
2063
+ uniqueIdProperty,
2064
+ storeGeometry,
2065
+ geometryIntersection
2066
+ });
2067
+ }
2068
+ }
2069
+ function getIndices(data) {
2070
+ let indices;
2071
+ switch (data.type) {
2072
+ case 'Point':
2073
+ // @ts-expect-error Missing or changed types?
2074
+ indices = data.pointIndices;
2075
+ break;
2076
+ case 'LineString':
2077
+ indices = data.pathIndices;
2078
+ break;
2079
+ case 'Polygon':
2080
+ indices = data.primitivePolygonIndices;
2081
+ break;
2082
+ default:
2083
+ throw new Error(`Unexpected type, "${data.type}"`);
2084
+ }
2085
+ return indices.value;
2086
+ }
2087
+ function getFeatureId(data, startIndex) {
2088
+ return data.featureIds.value[startIndex];
2089
+ }
2090
+ function getPropertiesFromTile(data, startIndex) {
2091
+ const featureId = getFeatureId(data, startIndex);
2092
+ const {
2093
+ properties,
2094
+ numericProps,
2095
+ fields
2096
+ } = data;
2097
+ const result = {
2098
+ uniqueId: fields?.[featureId]?.id,
2099
+ properties: properties[featureId],
2100
+ numericProps: {}
2101
+ };
2102
+ for (const key in numericProps) {
2103
+ result.numericProps[key] = numericProps[key].value[startIndex];
2104
+ }
2105
+ return result;
2106
+ }
2107
+ function parseProperties(tileProps) {
2108
+ const {
2109
+ properties,
2110
+ numericProps
2111
+ } = tileProps;
2112
+ return Object.assign({}, properties, numericProps);
2113
+ }
2114
+ function getUniquePropertyValue(tileProps, uniqueIdProperty, map) {
2115
+ if (uniqueIdProperty) {
2116
+ return getValueFromTileProps(tileProps, uniqueIdProperty);
2117
+ }
2118
+ if (tileProps.uniqueId) {
2119
+ return tileProps.uniqueId;
2120
+ }
2121
+ const artificialId = map.size + 1; // a counter, assumed as a valid new id
2122
+ return getValueFromTileProps(tileProps, 'cartodb_id') || getValueFromTileProps(tileProps, 'geoid') || artificialId;
2123
+ }
2124
+ function getValueFromTileProps(tileProps, propertyName) {
2125
+ const {
2126
+ properties,
2127
+ numericProps
2128
+ } = tileProps;
2129
+ return numericProps[propertyName] || properties[propertyName];
2130
+ }
2131
+ function getFeatureByType(coordinates, type) {
2132
+ switch (type) {
2133
+ case 'Polygon':
2134
+ return {
2135
+ type: 'Polygon',
2136
+ coordinates: [coordinates]
2137
+ };
2138
+ case 'LineString':
2139
+ return {
2140
+ type: 'LineString',
2141
+ coordinates
2142
+ };
2143
+ case 'Point':
2144
+ return {
2145
+ type: 'Point',
2146
+ coordinates: coordinates[0]
2147
+ };
2148
+ default:
2149
+ throw new Error('Invalid geometry type');
2150
+ }
2151
+ }
2152
+ function getRingCoordinatesFor(startIndex, endIndex, positions) {
2153
+ const ringCoordinates = [];
2154
+ for (let j = startIndex; j < endIndex; j++) {
2155
+ ringCoordinates.push(Array.from(positions.value.subarray(j * positions.size, (j + 1) * positions.size)));
2156
+ }
2157
+ return ringCoordinates;
2158
+ }
2159
+ function calculateFeatures(_ref4) {
2160
+ let {
2161
+ map,
2162
+ tileIsFullyVisible,
2163
+ geometryIntersection,
2164
+ data,
2165
+ type,
2166
+ bbox,
2167
+ tileFormat,
2168
+ uniqueIdProperty,
2169
+ options
2170
+ } = _ref4;
2171
+ if (!data?.properties.length) {
2172
+ return;
2173
+ }
2174
+ if (tileIsFullyVisible) {
2175
+ addAllFeaturesInTile({
2176
+ map,
2177
+ data,
2178
+ type,
2179
+ bbox,
2180
+ tileFormat,
2181
+ uniqueIdProperty,
2182
+ options
2183
+ });
2184
+ } else {
2185
+ addIntersectedFeaturesInTile({
2186
+ map,
2187
+ data,
2188
+ geometryIntersection,
2189
+ type,
2190
+ bbox,
2191
+ tileFormat,
2192
+ uniqueIdProperty,
2193
+ options
2194
+ });
2195
+ }
2196
+ }
2197
+ function addAllFeaturesInTile(_ref5) {
2198
+ let {
2199
+ map,
2200
+ data,
2201
+ type,
2202
+ bbox,
2203
+ tileFormat,
2204
+ uniqueIdProperty,
2205
+ options
2206
+ } = _ref5;
2207
+ const indices = getIndices(data);
2208
+ const storeGeometry = options?.storeGeometry || false;
2209
+ for (let i = 0; i < indices.length - 1; i++) {
2210
+ const startIndex = indices[i];
2211
+ const endIndex = indices[i + 1];
2212
+ processTileFeatureProperties({
2213
+ map,
2214
+ data,
2215
+ startIndex,
2216
+ endIndex,
2217
+ type,
2218
+ bbox,
2219
+ tileFormat,
2220
+ uniqueIdProperty,
2221
+ storeGeometry
2222
+ });
2223
+ }
2224
+ }
2225
+ function createIndicesForPoints(data) {
2226
+ const featureIds = data.featureIds.value;
2227
+ const lastFeatureId = featureIds[featureIds.length - 1];
2228
+ const PointIndicesArray = featureIds.constructor;
2229
+ const pointIndices = {
2230
+ value: new PointIndicesArray(featureIds.length + 1),
2231
+ size: 1
2232
+ };
2233
+ pointIndices.value.set(featureIds);
2234
+ pointIndices.value.set([lastFeatureId + 1], featureIds.length);
2235
+ // @ts-expect-error Missing or changed types?
2236
+ data.pointIndices = pointIndices;
2237
+ }
2238
+
2239
+ // a tile is an array [x,y,z]
2240
+ var d2r = Math.PI / 180,
2241
+ r2d = 180 / Math.PI;
2242
+ function tileToBBOX(tile) {
2243
+ var e = tile2lon(tile[0] + 1, tile[2]);
2244
+ var w = tile2lon(tile[0], tile[2]);
2245
+ var s = tile2lat(tile[1] + 1, tile[2]);
2246
+ var n = tile2lat(tile[1], tile[2]);
2247
+ return [w, s, e, n];
2248
+ }
2249
+ function tileToGeoJSON(tile) {
2250
+ var bbox = tileToBBOX(tile);
2251
+ var poly = {
2252
+ type: 'Polygon',
2253
+ coordinates: [[[bbox[0], bbox[1]], [bbox[0], bbox[3]], [bbox[2], bbox[3]], [bbox[2], bbox[1]], [bbox[0], bbox[1]]]]
2254
+ };
2255
+ return poly;
2256
+ }
2257
+ function tile2lon(x, z) {
2258
+ return x / Math.pow(2, z) * 360 - 180;
2259
+ }
2260
+ function tile2lat(y, z) {
2261
+ var n = Math.PI - 2 * Math.PI * y / Math.pow(2, z);
2262
+ return r2d * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)));
2263
+ }
2264
+ function pointToTile(lon, lat, z) {
2265
+ var tile = pointToTileFraction(lon, lat, z);
2266
+ tile[0] = Math.floor(tile[0]);
2267
+ tile[1] = Math.floor(tile[1]);
2268
+ return tile;
2269
+ }
2270
+ function getChildren(tile) {
2271
+ 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]];
2272
+ }
2273
+ function getParent(tile) {
2274
+ // top left
2275
+ if (tile[0] % 2 === 0 && tile[1] % 2 === 0) {
2276
+ return [tile[0] / 2, tile[1] / 2, tile[2] - 1];
2277
+ }
2278
+ // bottom left
2279
+ else if (tile[0] % 2 === 0 && !tile[1] % 2 === 0) {
2280
+ return [tile[0] / 2, (tile[1] - 1) / 2, tile[2] - 1];
2281
+ }
2282
+ // top right
2283
+ else if (!tile[0] % 2 === 0 && tile[1] % 2 === 0) {
2284
+ return [(tile[0] - 1) / 2, tile[1] / 2, tile[2] - 1];
2285
+ }
2286
+ // bottom right
2287
+ else {
2288
+ return [(tile[0] - 1) / 2, (tile[1] - 1) / 2, tile[2] - 1];
2289
+ }
2290
+ }
2291
+ function getSiblings(tile) {
2292
+ return getChildren(getParent(tile));
2293
+ }
2294
+ function hasSiblings(tile, tiles) {
2295
+ var siblings = getSiblings(tile);
2296
+ for (var i = 0; i < siblings.length; i++) {
2297
+ if (!hasTile(tiles, siblings[i])) return false;
2298
+ }
2299
+ return true;
2300
+ }
2301
+ function hasTile(tiles, tile) {
2302
+ for (var i = 0; i < tiles.length; i++) {
2303
+ if (tilesEqual(tiles[i], tile)) return true;
2304
+ }
2305
+ return false;
2306
+ }
2307
+ function tilesEqual(tile1, tile2) {
2308
+ return tile1[0] === tile2[0] && tile1[1] === tile2[1] && tile1[2] === tile2[2];
2309
+ }
2310
+ function tileToQuadkey(tile) {
2311
+ var index = '';
2312
+ for (var z = tile[2]; z > 0; z--) {
2313
+ var b = 0;
2314
+ var mask = 1 << z - 1;
2315
+ if ((tile[0] & mask) !== 0) b++;
2316
+ if ((tile[1] & mask) !== 0) b += 2;
2317
+ index += b.toString();
2318
+ }
2319
+ return index;
2320
+ }
2321
+ function quadkeyToTile(quadkey) {
2322
+ var x = 0;
2323
+ var y = 0;
2324
+ var z = quadkey.length;
2325
+ for (var i = z; i > 0; i--) {
2326
+ var mask = 1 << i - 1;
2327
+ switch (quadkey[z - i]) {
2328
+ case '0':
2329
+ break;
2330
+ case '1':
2331
+ x |= mask;
2332
+ break;
2333
+ case '2':
2334
+ y |= mask;
2335
+ break;
2336
+ case '3':
2337
+ x |= mask;
2338
+ y |= mask;
2339
+ break;
2340
+ }
2341
+ }
2342
+ return [x, y, z];
2343
+ }
2344
+ function bboxToTile(bboxCoords) {
2345
+ var min = pointToTile(bboxCoords[0], bboxCoords[1], 32);
2346
+ var max = pointToTile(bboxCoords[2], bboxCoords[3], 32);
2347
+ var bbox = [min[0], min[1], max[0], max[1]];
2348
+ var z = getBboxZoom(bbox);
2349
+ if (z === 0) return [0, 0, 0];
2350
+ var x = bbox[0] >>> 32 - z;
2351
+ var y = bbox[1] >>> 32 - z;
2352
+ return [x, y, z];
2353
+ }
2354
+ function getBboxZoom(bbox) {
2355
+ var MAX_ZOOM = 28;
2356
+ for (var z = 0; z < MAX_ZOOM; z++) {
2357
+ var mask = 1 << 32 - (z + 1);
2358
+ if ((bbox[0] & mask) != (bbox[2] & mask) || (bbox[1] & mask) != (bbox[3] & mask)) {
2359
+ return z;
2360
+ }
2361
+ }
2362
+ return MAX_ZOOM;
2363
+ }
2364
+ function pointToTileFraction(lon, lat, z) {
2365
+ var sin = Math.sin(lat * d2r),
2366
+ z2 = Math.pow(2, z),
2367
+ x = z2 * (lon / 360 + 0.5),
2368
+ y = z2 * (0.5 - 0.25 * Math.log((1 + sin) / (1 - sin)) / Math.PI);
2369
+ return [x, y, z];
2370
+ }
2371
+ var tilebelt = {
2372
+ tileToGeoJSON: tileToGeoJSON,
2373
+ tileToBBOX: tileToBBOX,
2374
+ getChildren: getChildren,
2375
+ getParent: getParent,
2376
+ getSiblings: getSiblings,
2377
+ hasTile: hasTile,
2378
+ hasSiblings: hasSiblings,
2379
+ tilesEqual: tilesEqual,
2380
+ tileToQuadkey: tileToQuadkey,
2381
+ quadkeyToTile: quadkeyToTile,
2382
+ pointToTile: pointToTile,
2383
+ bboxToTile: bboxToTile,
2384
+ pointToTileFraction: pointToTileFraction
2385
+ };
2386
+
2387
+ /**
2388
+ * Given a geometry, create cells and return them in their raw form,
2389
+ * as an array of cell identifiers.
2390
+ *
2391
+ * @alias tiles
2392
+ * @param {Object} geom GeoJSON geometry
2393
+ * @param {Object} limits an object with min_zoom and max_zoom properties
2394
+ * specifying the minimum and maximum level to be tiled.
2395
+ * @returns {Array<Array<number>>} An array of tiles given as [x, y, z] arrays
2396
+ */
2397
+ var tiles = getTiles;
2398
+ function getTiles(geom, limits) {
2399
+ var i,
2400
+ tile,
2401
+ coords = geom.coordinates,
2402
+ maxZoom = limits.max_zoom,
2403
+ tileHash = {},
2404
+ tiles = [];
2405
+ if (geom.type === 'Point') {
2406
+ return [tilebelt.pointToTile(coords[0], coords[1], maxZoom)];
2407
+ } else if (geom.type === 'MultiPoint') {
2408
+ for (i = 0; i < coords.length; i++) {
2409
+ tile = tilebelt.pointToTile(coords[i][0], coords[i][1], maxZoom);
2410
+ tileHash[toID(tile[0], tile[1], tile[2])] = true;
2411
+ }
2412
+ } else if (geom.type === 'LineString') {
2413
+ lineCover(tileHash, coords, maxZoom);
2414
+ } else if (geom.type === 'MultiLineString') {
2415
+ for (i = 0; i < coords.length; i++) {
2416
+ lineCover(tileHash, coords[i], maxZoom);
2417
+ }
2418
+ } else if (geom.type === 'Polygon') {
2419
+ polygonCover(tileHash, tiles, coords, maxZoom);
2420
+ } else if (geom.type === 'MultiPolygon') {
2421
+ for (i = 0; i < coords.length; i++) {
2422
+ polygonCover(tileHash, tiles, coords[i], maxZoom);
2423
+ }
2424
+ } else {
2425
+ throw new Error('Geometry type not implemented');
2426
+ }
2427
+ if (limits.min_zoom !== maxZoom) {
2428
+ // sync tile hash and tile array so that both contain the same tiles
2429
+ var len = tiles.length;
2430
+ appendHashTiles(tileHash, tiles);
2431
+ for (i = 0; i < len; i++) {
2432
+ var t = tiles[i];
2433
+ tileHash[toID(t[0], t[1], t[2])] = true;
2434
+ }
2435
+ return mergeTiles(tileHash, tiles, limits);
2436
+ }
2437
+ appendHashTiles(tileHash, tiles);
2438
+ return tiles;
2439
+ }
2440
+ function mergeTiles(tileHash, tiles, limits) {
2441
+ var mergedTiles = [];
2442
+ for (var z = limits.max_zoom; z > limits.min_zoom; z--) {
2443
+ var parentTileHash = {};
2444
+ var parentTiles = [];
2445
+ for (var i = 0; i < tiles.length; i++) {
2446
+ var t = tiles[i];
2447
+ if (t[0] % 2 === 0 && t[1] % 2 === 0) {
2448
+ var id2 = toID(t[0] + 1, t[1], z),
2449
+ id3 = toID(t[0], t[1] + 1, z),
2450
+ id4 = toID(t[0] + 1, t[1] + 1, z);
2451
+ if (tileHash[id2] && tileHash[id3] && tileHash[id4]) {
2452
+ tileHash[toID(t[0], t[1], t[2])] = false;
2453
+ tileHash[id2] = false;
2454
+ tileHash[id3] = false;
2455
+ tileHash[id4] = false;
2456
+ var parentTile = [t[0] / 2, t[1] / 2, z - 1];
2457
+ if (z - 1 === limits.min_zoom) mergedTiles.push(parentTile);else {
2458
+ parentTileHash[toID(t[0] / 2, t[1] / 2, z - 1)] = true;
2459
+ parentTiles.push(parentTile);
2460
+ }
2461
+ }
2462
+ }
2463
+ }
2464
+ for (i = 0; i < tiles.length; i++) {
2465
+ t = tiles[i];
2466
+ if (tileHash[toID(t[0], t[1], t[2])]) mergedTiles.push(t);
2467
+ }
2468
+ tileHash = parentTileHash;
2469
+ tiles = parentTiles;
2470
+ }
2471
+ return mergedTiles;
2472
+ }
2473
+ function polygonCover(tileHash, tileArray, geom, zoom) {
2474
+ var intersections = [];
2475
+ for (var i = 0; i < geom.length; i++) {
2476
+ var ring = [];
2477
+ lineCover(tileHash, geom[i], zoom, ring);
2478
+ for (var j = 0, len = ring.length, k = len - 1; j < len; k = j++) {
2479
+ var m = (j + 1) % len;
2480
+ var y = ring[j][1];
2481
+
2482
+ // add interesction if it's not local extremum or duplicate
2483
+ if ((y > ring[k][1] || y > ring[m][1]) && (
2484
+ // not local minimum
2485
+ y < ring[k][1] || y < ring[m][1]) &&
2486
+ // not local maximum
2487
+ y !== ring[m][1]) intersections.push(ring[j]);
2488
+ }
2489
+ }
2490
+ intersections.sort(compareTiles); // sort by y, then x
2491
+
2492
+ for (i = 0; i < intersections.length; i += 2) {
2493
+ // fill tiles between pairs of intersections
2494
+ y = intersections[i][1];
2495
+ for (var x = intersections[i][0] + 1; x < intersections[i + 1][0]; x++) {
2496
+ var id = toID(x, y, zoom);
2497
+ if (!tileHash[id]) {
2498
+ tileArray.push([x, y, zoom]);
2499
+ }
2500
+ }
2501
+ }
2502
+ }
2503
+ function compareTiles(a, b) {
2504
+ return a[1] - b[1] || a[0] - b[0];
2505
+ }
2506
+ function lineCover(tileHash, coords, maxZoom, ring) {
2507
+ var prevX, prevY;
2508
+ for (var i = 0; i < coords.length - 1; i++) {
2509
+ var start = tilebelt.pointToTileFraction(coords[i][0], coords[i][1], maxZoom),
2510
+ stop = tilebelt.pointToTileFraction(coords[i + 1][0], coords[i + 1][1], maxZoom),
2511
+ x0 = start[0],
2512
+ y0 = start[1],
2513
+ x1 = stop[0],
2514
+ y1 = stop[1],
2515
+ dx = x1 - x0,
2516
+ dy = y1 - y0;
2517
+ if (dy === 0 && dx === 0) continue;
2518
+ var sx = dx > 0 ? 1 : -1,
2519
+ sy = dy > 0 ? 1 : -1,
2520
+ x = Math.floor(x0),
2521
+ y = Math.floor(y0),
2522
+ tMaxX = dx === 0 ? Infinity : Math.abs(((dx > 0 ? 1 : 0) + x - x0) / dx),
2523
+ tMaxY = dy === 0 ? Infinity : Math.abs(((dy > 0 ? 1 : 0) + y - y0) / dy),
2524
+ tdx = Math.abs(sx / dx),
2525
+ tdy = Math.abs(sy / dy);
2526
+ if (x !== prevX || y !== prevY) {
2527
+ tileHash[toID(x, y, maxZoom)] = true;
2528
+ if (ring && y !== prevY) ring.push([x, y]);
2529
+ prevX = x;
2530
+ prevY = y;
2531
+ }
2532
+ while (tMaxX < 1 || tMaxY < 1) {
2533
+ if (tMaxX < tMaxY) {
2534
+ tMaxX += tdx;
2535
+ x += sx;
2536
+ } else {
2537
+ tMaxY += tdy;
2538
+ y += sy;
2539
+ }
2540
+ tileHash[toID(x, y, maxZoom)] = true;
2541
+ if (ring && y !== prevY) ring.push([x, y]);
2542
+ prevX = x;
2543
+ prevY = y;
2544
+ }
2545
+ }
2546
+ if (ring && y === ring[0][1]) ring.pop();
2547
+ }
2548
+ function appendHashTiles(hash, tiles) {
2549
+ var keys = Object.keys(hash);
2550
+ for (var i = 0; i < keys.length; i++) {
2551
+ tiles.push(fromID(+keys[i]));
2552
+ }
2553
+ }
2554
+ function toID(x, y, z) {
2555
+ var dim = 2 * (1 << z);
2556
+ return (dim * y + x) * 32 + z;
2557
+ }
2558
+ function fromID(id) {
2559
+ var z = id % 32,
2560
+ dim = 2 * (1 << z),
2561
+ xy = (id - z) / 32,
2562
+ x = xy % dim,
2563
+ y = (xy - x) / dim % dim;
2564
+ return [x, y, z];
2565
+ }
2566
+
2567
+ const B = [0x5555555555555555n, 0x3333333333333333n, 0x0f0f0f0f0f0f0f0fn, 0x00ff00ff00ff00ffn, 0x0000ffff0000ffffn, 0x00000000ffffffffn];
2568
+ const S = [0n, 1n, 2n, 4n, 8n, 16n];
2569
+ function tileToCell(tile) {
2570
+ if (tile.z < 0 || tile.z > 26) {
2571
+ throw new Error('Wrong zoom');
2572
+ }
2573
+ const z = BigInt(tile.z);
2574
+ let x = BigInt(tile.x) << 32n - z;
2575
+ let y = BigInt(tile.y) << 32n - z;
2576
+ for (let i = 0; i < 5; i++) {
2577
+ const s = S[5 - i];
2578
+ const b = B[4 - i];
2579
+ x = (x | x << s) & b;
2580
+ y = (y | y << s) & b;
2581
+ }
2582
+ const quadbin = 0x4000000000000000n | 1n << 59n |
2583
+ // | (mode << 59) | (mode_dep << 57)
2584
+ z << 52n | (x | y << 1n) >> 12n | 0xfffffffffffffn >> z * 2n;
2585
+ return quadbin;
2586
+ }
2587
+ function getResolution$1(quadbin) {
2588
+ return quadbin >> 52n & 0x1fn;
2589
+ }
2590
+ function geometryToCells(geometry, resolution) {
2591
+ const zoom = Number(resolution);
2592
+ return tiles(geometry, {
2593
+ min_zoom: zoom,
2594
+ max_zoom: zoom
2595
+ }).map(([x, y, z]) => tileToCell({
2596
+ x,
2597
+ y,
2598
+ z
2599
+ }));
2600
+ }
2601
+
2602
+ function tileFeaturesSpatialIndex(_ref) {
2603
+ let {
2604
+ tiles,
2605
+ spatialFilter,
2606
+ spatialDataColumn,
2607
+ spatialDataType
2608
+ } = _ref;
2609
+ const map = new Map();
2610
+ const spatialIndex = getSpatialIndex(spatialDataType);
2611
+ const resolution = getResolution(tiles, spatialIndex);
2612
+ const spatialIndexIDName = spatialDataColumn ? spatialDataColumn : spatialIndex;
2613
+ if (!resolution) {
2614
+ return [];
2615
+ }
2616
+ const cells = getCellsCoverGeometry(spatialFilter, spatialIndex, resolution);
2617
+ if (!cells?.length) {
2618
+ return [];
2619
+ }
2620
+ // We transform cells to Set to improve the performace
2621
+ const cellsSet = new Set(cells);
2622
+ for (const tile of tiles) {
2623
+ if (tile.isVisible === false || !tile.data) {
2624
+ continue;
2625
+ }
2626
+ tile.data.forEach(d => {
2627
+ if (cellsSet.has(d.id)) {
2628
+ map.set(d.id, {
2629
+ ...d.properties,
2630
+ [spatialIndexIDName]: d.id
2631
+ });
2632
+ }
2633
+ });
2634
+ }
2635
+ return Array.from(map.values());
2636
+ }
2637
+ function getResolution(tiles, spatialIndex) {
2638
+ const data = tiles.find(tile => tile.data?.length)?.data;
2639
+ if (!data) {
2640
+ return;
2641
+ }
2642
+ if (spatialIndex === exports.SpatialIndex.QUADBIN) {
2643
+ return Number(getResolution$1(data[0].id));
2644
+ }
2645
+ if (spatialIndex === exports.SpatialIndex.H3) {
2646
+ return h3Js.getResolution(data[0].id);
2647
+ }
2648
+ }
2649
+ const bboxWest = [-180, -90, 0, 90];
2650
+ const bboxEast = [0, -90, 180, 90];
2651
+ function getCellsCoverGeometry(geometry, spatialIndex, resolution) {
2652
+ if (spatialIndex === exports.SpatialIndex.QUADBIN) {
2653
+ // @ts-expect-error TODO: Probably ought to be stricter about number vs. bigint types in this file.
2654
+ return geometryToCells(geometry, resolution);
2655
+ }
2656
+ if (spatialIndex === exports.SpatialIndex.H3) {
2657
+ // The current H3 polyfill algorithm can't deal with polygon segments of greater than 180 degrees longitude
2658
+ // so we clip the geometry to be sure that none of them is greater than 180 degrees
2659
+ // https://github.com/uber/h3-js/issues/24#issuecomment-431893796
2660
+ return h3Js.polygonToCells(bboxClip(geometry, bboxWest).geometry.coordinates, resolution, true).concat(h3Js.polygonToCells(bboxClip(geometry, bboxEast).geometry.coordinates, resolution, true));
2661
+ }
2662
+ }
2663
+ function getSpatialIndex(spatialDataType) {
2664
+ switch (spatialDataType) {
2665
+ case 'h3':
2666
+ return exports.SpatialIndex.H3;
2667
+ case 'quadbin':
2668
+ return exports.SpatialIndex.QUADBIN;
2669
+ default:
2670
+ throw new Error('Unexpected spatial data type');
2671
+ }
2672
+ }
2673
+
2674
+ /** @internalRemarks Source: @carto/react-core */
2675
+ function tileFeatures(_ref) {
2676
+ let {
2677
+ tiles,
2678
+ spatialFilter,
2679
+ uniqueIdProperty,
2680
+ tileFormat,
2681
+ spatialDataColumn = DEFAULT_GEO_COLUMN,
2682
+ spatialDataType,
2683
+ options = {}
2684
+ } = _ref;
2685
+ // TODO(cleanup): Is an empty response the expected result when spatialFilter
2686
+ // is omitted? Why not make the parameter required, or return the full input?
2687
+ if (!spatialFilter) {
2688
+ return [];
2689
+ }
2690
+ if (spatialDataType !== 'geo') {
2691
+ return tileFeaturesSpatialIndex({
2692
+ tiles: tiles,
2693
+ spatialFilter,
2694
+ spatialDataColumn,
2695
+ spatialDataType
2696
+ });
2697
+ }
2698
+ return tileFeaturesGeometries({
2699
+ tiles,
2700
+ tileFormat,
2701
+ spatialFilter,
2702
+ uniqueIdProperty,
2703
+ options
2704
+ });
2705
+ }
2706
+
2707
+ /** @internalRemarks Source: @carto/react-core */
2708
+ const aggregationFunctions = {
2709
+ count: values => values.length,
2710
+ min: function () {
2711
+ return applyAggregationFunction(min, ...[].slice.call(arguments));
2712
+ },
2713
+ max: function () {
2714
+ return applyAggregationFunction(max, ...[].slice.call(arguments));
2715
+ },
2716
+ sum: function () {
2717
+ return applyAggregationFunction(sum, ...[].slice.call(arguments));
2718
+ },
2719
+ avg: function () {
2720
+ return applyAggregationFunction(avg, ...[].slice.call(arguments));
2721
+ }
2722
+ };
2723
+ /** @internalRemarks Source: @carto/react-core */
2724
+ function aggregate(feature, keys, operation) {
2725
+ if (!keys?.length) {
2726
+ throw new Error('Cannot aggregate a feature without having keys');
2727
+ } else if (keys.length === 1) {
2728
+ const value = feature[keys[0]];
2729
+ return isPotentiallyValidNumber(value) ? Number(value) : value;
2730
+ }
2731
+ const aggregationFn = aggregationFunctions[operation];
2732
+ if (!aggregationFn) {
2733
+ throw new Error(`${operation} isn't a valid aggregation function`);
2734
+ }
2735
+ return aggregationFn(keys.map(column => {
2736
+ const value = feature[column];
2737
+ return isPotentiallyValidNumber(value) ? Number(value) : value;
2738
+ }));
2739
+ }
2740
+ /*
2741
+ * Forced casting to Number (just of non empty strings) allows to work-around
2742
+ * some specific situations, where a big numeric field is transformed into a string when generating the tileset(eg.PG)
2743
+ */
2744
+ function isPotentiallyValidNumber(value) {
2745
+ return typeof value === 'string' && value.trim().length > 0;
2746
+ }
2747
+ const applyAggregationFunction = (aggFn, values, keys, operation) => {
2748
+ const normalizedKeys = normalizeKeys(keys);
2749
+ const elements = (normalizedKeys?.length || 0) <= 1 ? filterFalsyElements(values, normalizedKeys || []) : values;
2750
+ return aggFn(elements, keys, operation);
2751
+ };
2752
+ function filterFalsyElements(values, keys) {
2753
+ const filterFn = value => value !== null && value !== undefined;
2754
+ if (!keys?.length) {
2755
+ return values.filter(filterFn);
2756
+ }
2757
+ return values.filter(v => filterFn(v[keys[0]]));
2758
+ }
2759
+ // Aggregation functions
2760
+ function avg(values, keys, joinOperation) {
2761
+ return sum(values, keys, joinOperation) / (values.length || 1);
2762
+ }
2763
+ function sum(values, keys, joinOperation) {
2764
+ const normalizedKeys = normalizeKeys(keys);
2765
+ if (normalizedKeys) {
2766
+ return values.reduce((a, b) => a + aggregate(b, normalizedKeys, joinOperation), 0);
2767
+ }
2768
+ return values.reduce((a, b) => a + b, 0);
2769
+ }
2770
+ function min(values, keys, joinOperation) {
2771
+ const normalizedKeys = normalizeKeys(keys);
2772
+ if (normalizedKeys) {
2773
+ return values.reduce((a, b) => Math.min(a, aggregate(b, normalizedKeys, joinOperation)), Infinity);
2774
+ }
2775
+ return Math.min(...values);
2776
+ }
2777
+ function max(values, keys, joinOperation) {
2778
+ const normalizedKeys = normalizeKeys(keys);
2779
+ if (normalizedKeys) {
2780
+ return values.reduce((a, b) => Math.max(a, aggregate(b, normalizedKeys, joinOperation)), -Infinity);
2781
+ }
2782
+ return Math.max(...values);
2783
+ }
2784
+ // Aux
2785
+ // Keys can come as a string (one column) or a strings array (multiple column)
2786
+ // Use always an array to make the code easier
2787
+ function normalizeKeys(keys) {
2788
+ return Array.isArray(keys) ? keys : typeof keys === 'string' ? [keys] : undefined;
2789
+ }
2790
+
2791
+ /***
2792
+ Copyright 2013 Teun Duynstee
2793
+
2794
+ Licensed under the Apache License, Version 2.0 (the "License");
2795
+ you may not use this file except in compliance with the License.
2796
+ You may obtain a copy of the License at
2797
+
2798
+ http://www.apache.org/licenses/LICENSE-2.0
2799
+
2800
+ Unless required by applicable law or agreed to in writing, software
2801
+ distributed under the License is distributed on an "AS IS" BASIS,
2802
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2803
+ See the License for the specific language governing permissions and
2804
+ limitations under the License.
2805
+ */
2806
+ var thenBy_module = function () {
2807
+ function identity(v) {
2808
+ return v;
2809
+ }
2810
+ function ignoreCase(v) {
2811
+ return typeof v === "string" ? v.toLowerCase() : v;
2812
+ }
2813
+ function makeCompareFunction(f, opt) {
2814
+ opt = typeof opt === "object" ? opt : {
2815
+ direction: opt
2816
+ };
2817
+ if (typeof f != "function") {
2818
+ var prop = f;
2819
+ // make unary function
2820
+ f = function (v1) {
2821
+ return !!v1[prop] ? v1[prop] : "";
2822
+ };
2823
+ }
2824
+ if (f.length === 1) {
2825
+ // f is a unary function mapping a single item to its sort score
2826
+ var uf = f;
2827
+ var preprocess = opt.ignoreCase ? ignoreCase : identity;
2828
+ var cmp = opt.cmp || function (v1, v2) {
2829
+ return v1 < v2 ? -1 : v1 > v2 ? 1 : 0;
2830
+ };
2831
+ f = function (v1, v2) {
2832
+ return cmp(preprocess(uf(v1)), preprocess(uf(v2)));
2833
+ };
2834
+ }
2835
+ const descTokens = {
2836
+ "-1": '',
2837
+ desc: ''
2838
+ };
2839
+ if (opt.direction in descTokens) return function (v1, v2) {
2840
+ return -f(v1, v2);
2841
+ };
2842
+ return f;
2843
+ }
2844
+
2845
+ /* adds a secondary compare function to the target function (`this` context)
2846
+ which is applied in case the first one returns 0 (equal)
2847
+ returns a new compare function, which has a `thenBy` method as well */
2848
+ function tb(func, opt) {
2849
+ /* should get value false for the first call. This can be done by calling the
2850
+ exported function, or the firstBy property on it (for es6 module compatibility)
2851
+ */
2852
+ var x = typeof this == "function" && !this.firstBy ? this : false;
2853
+ var y = makeCompareFunction(func, opt);
2854
+ var f = x ? function (a, b) {
2855
+ return x(a, b) || y(a, b);
2856
+ } : y;
2857
+ f.thenBy = tb;
2858
+ return f;
2859
+ }
2860
+ tb.firstBy = tb;
2861
+ return tb;
2862
+ }();
2863
+
2864
+ /**
2865
+ * Apply sort structure to a collection of features
2866
+ * @param features
2867
+ * @param [sortOptions]
2868
+ * @param [sortOptions.sortBy] - One or more columns to sort by
2869
+ * @param [sortOptions.sortByDirection] - Direction by the columns will be sorted
2870
+ * @param [sortOptions.sortByColumnType] - Column type
2871
+ * @internal
2872
+ * @internalRemarks Source: @carto/react-core
2873
+ */
2874
+ function applySorting(features, _temp) {
2875
+ let {
2876
+ sortBy,
2877
+ sortByDirection = 'asc',
2878
+ sortByColumnType = 'string'
2879
+ } = _temp === void 0 ? {} : _temp;
2880
+ // If sortBy is undefined, pass all features
2881
+ if (sortBy === undefined) {
2882
+ return features;
2883
+ }
2884
+ // sortOptions exists, but are bad formatted
2885
+ const isValidSortBy = Array.isArray(sortBy) && sortBy.length ||
2886
+ // sortBy can be an array of columns
2887
+ typeof sortBy === 'string'; // or just one column
2888
+ if (!isValidSortBy) {
2889
+ throw new Error('Sorting options are bad formatted');
2890
+ }
2891
+ const sortFn = createSortFn({
2892
+ sortBy,
2893
+ sortByDirection,
2894
+ sortByColumnType: sortByColumnType || 'string'
2895
+ });
2896
+ return features.sort(sortFn);
2897
+ }
2898
+ // Aux
2899
+ function createSortFn(_ref) {
2900
+ let {
2901
+ sortBy,
2902
+ sortByDirection,
2903
+ sortByColumnType
2904
+ } = _ref;
2905
+ const [firstSortOption, ...othersSortOptions] = normalizeSortByOptions({
2906
+ sortBy,
2907
+ sortByDirection,
2908
+ sortByColumnType
2909
+ });
2910
+ let sortFn = thenBy_module.firstBy(...firstSortOption);
2911
+ for (let sortOptions of othersSortOptions) {
2912
+ sortFn = sortFn.thenBy(...sortOptions);
2913
+ }
2914
+ return sortFn;
2915
+ }
2916
+ function normalizeSortByOptions(_ref2) {
2917
+ let {
2918
+ sortBy,
2919
+ sortByDirection,
2920
+ sortByColumnType
2921
+ } = _ref2;
2922
+ const numberFormat = sortByColumnType === 'number' && {
2923
+ cmp: (a, b) => a - b
2924
+ };
2925
+ if (!Array.isArray(sortBy)) {
2926
+ sortBy = [sortBy];
2927
+ }
2928
+ return sortBy.map(sortByEl => {
2929
+ // sortByEl is 'column'
2930
+ if (typeof sortByEl === 'string') {
2931
+ return [sortByEl, {
2932
+ direction: sortByDirection,
2933
+ ...numberFormat
2934
+ }];
2935
+ }
2936
+ if (Array.isArray(sortByEl)) {
2937
+ // sortBy is ['column']
2938
+ if (sortByEl[1] === undefined) {
2939
+ return [sortByEl, {
2940
+ direction: sortByDirection,
2941
+ ...numberFormat
2942
+ }];
2943
+ }
2944
+ // sortBy is ['column', { ... }]
2945
+ if (typeof sortByEl[1] === 'object') {
2946
+ const othersSortOptions = numberFormat ? {
2947
+ ...numberFormat,
2948
+ ...sortByEl[1]
2949
+ } : sortByEl[1];
2950
+ return [sortByEl[0], {
2951
+ direction: sortByDirection,
2952
+ ...othersSortOptions
2953
+ }];
2954
+ }
2955
+ }
2956
+ return sortByEl;
2957
+ });
2958
+ }
2959
+
2960
+ /** @internalRemarks Source: @carto/react-core */
2961
+ function groupValuesByColumn(_ref) {
2962
+ let {
2963
+ data,
2964
+ valuesColumns,
2965
+ joinOperation,
2966
+ keysColumn,
2967
+ operation
2968
+ } = _ref;
2969
+ if (Array.isArray(data) && data.length === 0) {
2970
+ return null;
2971
+ }
2972
+ const groups = data.reduce((accumulator, item) => {
2973
+ const group = item[keysColumn];
2974
+ const values = accumulator.get(group) || [];
2975
+ accumulator.set(group, values);
2976
+ const aggregatedValue = aggregate(item, valuesColumns, joinOperation);
2977
+ const isValid = (operation === 'count' ? true : aggregatedValue !== null) && aggregatedValue !== undefined;
2978
+ if (isValid) {
2979
+ values.push(aggregatedValue);
2980
+ accumulator.set(group, values);
2981
+ }
2982
+ return accumulator;
2983
+ }, new Map()); // We use a map to be able to maintain the type in the key value
2984
+ const targetOperation = aggregationFunctions[operation];
2985
+ if (targetOperation) {
2986
+ return Array.from(groups).map(_ref2 => {
2987
+ let [name, value] = _ref2;
2988
+ return {
2989
+ name,
2990
+ value: targetOperation(value)
2991
+ };
2992
+ });
2993
+ }
2994
+ return [];
2995
+ }
2996
+
2997
+ /**
2998
+ * Returns midnight (local time) on the Monday preceeding a given date, in
2999
+ * milliseconds since the UNIX epoch.
3000
+ */
3001
+ /**
3002
+ * Returns midnight (UTC) on the Monday preceeding a given date, in
3003
+ * milliseconds since the UNIX epoch.
3004
+ */
3005
+ function getUTCMonday(date) {
3006
+ const dateCp = new Date(date);
3007
+ const day = dateCp.getUTCDay();
3008
+ const diff = dateCp.getUTCDate() - day + (day ? 1 : -6); // adjust when day is sunday
3009
+ dateCp.setUTCDate(diff);
3010
+ return Date.UTC(dateCp.getUTCFullYear(), dateCp.getUTCMonth(), dateCp.getUTCDate());
3011
+ }
3012
+
3013
+ const GROUP_KEY_FN_MAPPING = {
3014
+ year: date => Date.UTC(date.getUTCFullYear()),
3015
+ month: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth()),
3016
+ week: date => getUTCMonday(date),
3017
+ day: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()),
3018
+ hour: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours()),
3019
+ minute: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes()),
3020
+ second: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds())
3021
+ };
3022
+ /** @internalRemarks Source: @carto/react-core */
3023
+ function groupValuesByDateColumn(_ref) {
3024
+ let {
3025
+ data,
3026
+ valuesColumns,
3027
+ joinOperation,
3028
+ keysColumn,
3029
+ groupType,
3030
+ operation
3031
+ } = _ref;
3032
+ if (Array.isArray(data) && data.length === 0) {
3033
+ return null;
3034
+ }
3035
+ const groupKeyFn = GROUP_KEY_FN_MAPPING[groupType];
3036
+ if (!groupKeyFn) {
3037
+ return null;
3038
+ }
3039
+ const groups = data.reduce((acc, item) => {
3040
+ const value = item[keysColumn];
3041
+ const formattedValue = new Date(value);
3042
+ const groupKey = groupKeyFn(formattedValue);
3043
+ if (!isNaN(groupKey)) {
3044
+ let groupedValues = acc.get(groupKey);
3045
+ if (!groupedValues) {
3046
+ groupedValues = [];
3047
+ acc.set(groupKey, groupedValues);
3048
+ }
3049
+ const aggregatedValue = aggregate(item, valuesColumns, joinOperation);
3050
+ const isValid = aggregatedValue !== null && aggregatedValue !== undefined;
3051
+ if (isValid) {
3052
+ groupedValues.push(aggregatedValue);
3053
+ acc.set(groupKey, groupedValues);
3054
+ }
3055
+ }
3056
+ return acc;
3057
+ }, new Map());
3058
+ const targetOperation = aggregationFunctions[operation];
3059
+ return [...groups.entries()].map(_ref2 => {
3060
+ let [name, value] = _ref2;
3061
+ return {
3062
+ name,
3063
+ value: targetOperation(value)
3064
+ };
3065
+ }).sort((a, b) => a.name - b.name);
3066
+ }
3067
+
3068
+ /**
3069
+ * Histogram computation.
3070
+ * @internalRemarks Source: @carto/react-core
3071
+ */
3072
+ function histogram(_ref) {
3073
+ let {
3074
+ data,
3075
+ valuesColumns,
3076
+ joinOperation,
3077
+ ticks,
3078
+ operation
3079
+ } = _ref;
3080
+ if (Array.isArray(data) && data.length === 0) {
3081
+ return [];
3082
+ }
3083
+ const binsContainer = [Number.MIN_SAFE_INTEGER, ...ticks].map((tick, index, arr) => ({
3084
+ bin: index,
3085
+ start: tick,
3086
+ end: index === arr.length - 1 ? Number.MAX_SAFE_INTEGER : arr[index + 1],
3087
+ values: []
3088
+ }));
3089
+ data.forEach(feature => {
3090
+ const featureValue = aggregate(feature, valuesColumns, joinOperation);
3091
+ const isValid = featureValue !== null && featureValue !== undefined;
3092
+ if (!isValid) {
3093
+ return;
3094
+ }
3095
+ const binContainer = binsContainer.find(bin => bin.start <= featureValue && bin.end > featureValue);
3096
+ if (!binContainer) {
3097
+ return;
3098
+ }
3099
+ binContainer.values.push(featureValue);
3100
+ });
3101
+ const targetOperation = aggregationFunctions[operation];
3102
+ const transformedBins = binsContainer.map(binContainer => binContainer.values);
3103
+ return transformedBins.map(values => values.length ? targetOperation(values) : 0);
3104
+ }
3105
+
3106
+ /**
3107
+ * Filters invalid features and formats data.
3108
+ * @internalRemarks Source: @carto/react-core
3109
+ */
3110
+ function scatterPlot(_ref) {
3111
+ let {
3112
+ data,
3113
+ xAxisColumns,
3114
+ xAxisJoinOperation,
3115
+ yAxisColumns,
3116
+ yAxisJoinOperation
3117
+ } = _ref;
3118
+ return data.reduce((acc, feature) => {
3119
+ const xValue = aggregate(feature, xAxisColumns, xAxisJoinOperation);
3120
+ const xIsValid = xValue !== null && xValue !== undefined;
3121
+ const yValue = aggregate(feature, yAxisColumns, yAxisJoinOperation);
3122
+ const yIsValid = yValue !== null && yValue !== undefined;
3123
+ if (xIsValid && yIsValid) {
3124
+ acc.push([xValue, yValue]);
3125
+ }
3126
+ return acc;
3127
+ }, []);
3128
+ }
3129
+
3130
+ /**
3131
+ * Source for Widget API requests on a data source defined by a tileset.
3132
+ *
3133
+ * Generally not intended to be constructed directly. Instead, call
3134
+ * {@link vectorTilesetSource}, {@link h3TilesetSource}, or {@link quadbinTilesetSource},
3135
+ * which can be shared with map layers. Sources contain a `widgetSource`
3136
+ * property, for use by widget implementations.
3137
+ *
3138
+ * Example:
3139
+ *
3140
+ * ```javascript
3141
+ * import { vectorTilesetSource } from '@carto/api-client';
3142
+ *
3143
+ * const data = vectorTilesetSource({
3144
+ * accessToken: '••••',
3145
+ * connectionName: 'carto_dw',
3146
+ * tableName: 'carto-demo-data.demo_rasters.my_tileset_source'
3147
+ * });
3148
+ *
3149
+ * const { widgetSource } = await data;
3150
+ * ```
3151
+ */
3152
+ class WidgetTilesetSource extends WidgetSource {
3153
+ constructor() {
3154
+ super(...arguments);
3155
+ this._features = [];
3156
+ }
3157
+ getModelSource(owner) {
3158
+ return {
3159
+ ...super._getModelSource(owner),
3160
+ type: 'tileset',
3161
+ data: this.props.tableName
3162
+ };
3163
+ }
3164
+ /** Loads features as a list of tiles (typically provided by deck.gl). */
3165
+ loadTiles(_ref) {
3166
+ let {
3167
+ tiles,
3168
+ spatialFilter,
3169
+ uniqueIdProperty,
3170
+ options
3171
+ } = _ref;
3172
+ this._features = tileFeatures({
3173
+ tiles,
3174
+ options,
3175
+ spatialFilter,
3176
+ uniqueIdProperty,
3177
+ tileFormat: this.props.tileFormat,
3178
+ spatialDataColumn: this.props.spatialDataColumn,
3179
+ spatialDataType: this.props.spatialDataType
3180
+ });
3181
+ }
3182
+ /** Loads features as GeoJSON (used for testing). */
3183
+ loadGeoJSON(_ref2) {
3184
+ let {
3185
+ geojson,
3186
+ spatialFilter,
3187
+ uniqueIdProperty
3188
+ } = _ref2;
3189
+ this._features = geojsonFeatures({
3190
+ geojson,
3191
+ spatialFilter,
3192
+ uniqueIdProperty
3193
+ });
3194
+ }
3195
+ getFeatures(options) {
3196
+ try {
3197
+ throw new Error('getFeatures not supported for tilesets');
3198
+ return Promise.resolve();
3199
+ } catch (e) {
3200
+ return Promise.reject(e);
3201
+ }
3202
+ }
3203
+ getFormula(_ref3) {
3204
+ let {
3205
+ column = '*',
3206
+ operation = 'count',
3207
+ joinOperation,
3208
+ filterOwner
3209
+ } = _ref3;
3210
+ try {
3211
+ const _this = this;
3212
+ if (operation === 'custom') {
3213
+ throw new Error('Custom aggregation not supported for tilesets');
3214
+ }
3215
+ if (!_this._features.length) {
3216
+ return Promise.resolve({
3217
+ value: null
3218
+ });
3219
+ }
3220
+ // Column is required except when operation is 'count'.
3221
+ if (column && column !== '*' || operation !== 'count') {
3222
+ assertColumn(_this._features, column);
3223
+ }
3224
+ const filteredFeatures = _this._getFilteredFeatures(filterOwner);
3225
+ if (filteredFeatures.length === 0 && operation !== 'count') {
3226
+ return Promise.resolve({
3227
+ value: null
3228
+ });
3229
+ }
3230
+ const targetOperation = aggregationFunctions[operation];
3231
+ return Promise.resolve({
3232
+ value: targetOperation(filteredFeatures, column, joinOperation)
3233
+ });
3234
+ } catch (e) {
3235
+ return Promise.reject(e);
3236
+ }
3237
+ }
3238
+ getHistogram(_ref4) {
3239
+ let {
3240
+ operation = 'count',
3241
+ ticks,
3242
+ column,
3243
+ joinOperation,
3244
+ filterOwner
3245
+ } = _ref4;
3246
+ try {
3247
+ const _this2 = this;
3248
+ if (!_this2._features.length) {
3249
+ return Promise.resolve([]);
3250
+ }
3251
+ const filteredFeatures = _this2._getFilteredFeatures(filterOwner);
3252
+ assertColumn(_this2._features, column);
3253
+ return Promise.resolve(histogram({
3254
+ data: filteredFeatures,
3255
+ valuesColumns: normalizeColumns(column),
3256
+ joinOperation,
3257
+ ticks,
3258
+ operation
3259
+ }));
3260
+ } catch (e) {
3261
+ return Promise.reject(e);
3262
+ }
3263
+ }
3264
+ getCategories(_ref5) {
3265
+ let {
3266
+ column,
3267
+ operation = 'count',
3268
+ operationColumn,
3269
+ joinOperation,
3270
+ filterOwner
3271
+ } = _ref5;
3272
+ try {
3273
+ const _this3 = this;
3274
+ if (!_this3._features.length) {
3275
+ return Promise.resolve([]);
3276
+ }
3277
+ const filteredFeatures = _this3._getFilteredFeatures(filterOwner);
3278
+ assertColumn(_this3._features, column, operationColumn);
3279
+ const groups = groupValuesByColumn({
3280
+ data: filteredFeatures,
3281
+ valuesColumns: normalizeColumns(operationColumn || column),
3282
+ joinOperation,
3283
+ keysColumn: column,
3284
+ operation
3285
+ });
3286
+ return Promise.resolve(groups || []);
3287
+ } catch (e) {
3288
+ return Promise.reject(e);
3289
+ }
3290
+ }
3291
+ getScatter(_ref6) {
3292
+ let {
3293
+ xAxisColumn,
3294
+ yAxisColumn,
3295
+ xAxisJoinOperation,
3296
+ yAxisJoinOperation,
3297
+ filterOwner
3298
+ } = _ref6;
3299
+ try {
3300
+ const _this4 = this;
3301
+ if (!_this4._features.length) {
3302
+ return Promise.resolve([]);
3303
+ }
3304
+ const filteredFeatures = _this4._getFilteredFeatures(filterOwner);
3305
+ assertColumn(_this4._features, xAxisColumn, yAxisColumn);
3306
+ return Promise.resolve(scatterPlot({
3307
+ data: filteredFeatures,
3308
+ xAxisColumns: normalizeColumns(xAxisColumn),
3309
+ xAxisJoinOperation,
3310
+ yAxisColumns: normalizeColumns(yAxisColumn),
3311
+ yAxisJoinOperation
3312
+ }));
3313
+ } catch (e) {
3314
+ return Promise.reject(e);
3315
+ }
3316
+ }
3317
+ getTable(options) {
3318
+ try {
3319
+ const _this5 = this;
3320
+ const {
3321
+ filterOwner,
3322
+ spatialFilter,
3323
+ abortController,
3324
+ ...params
3325
+ } = options;
3326
+ const {
3327
+ columns,
3328
+ searchFilterColumn,
3329
+ searchFilterText,
3330
+ sortBy,
3331
+ sortDirection,
3332
+ sortByColumnType,
3333
+ offset = 0,
3334
+ limit = 10
3335
+ } = params;
3336
+ if (!_this5._features.length) {
3337
+ return Promise.resolve({
3338
+ rows: [],
3339
+ totalCount: 0
3340
+ });
3341
+ }
3342
+ // Filter.
3343
+ let filteredFeatures = _this5._getFilteredFeatures(filterOwner);
3344
+ // Search.
3345
+ // TODO: Could we get the same behavior by applying filters in loadTiles()?
3346
+ if (searchFilterColumn && searchFilterText) {
3347
+ filteredFeatures = filteredFeatures.filter(row => row[searchFilterColumn] && String(row[searchFilterColumn]).toLowerCase().includes(String(searchFilterText).toLowerCase()));
3348
+ }
3349
+ // Sort.
3350
+ let rows = applySorting(filteredFeatures, {
3351
+ sortBy,
3352
+ sortByDirection: sortDirection,
3353
+ sortByColumnType
3354
+ });
3355
+ const totalCount = rows.length;
3356
+ // Offset and limit.
3357
+ rows = rows.slice(Math.min(offset, totalCount), Math.min(offset + limit, totalCount));
3358
+ // Select columns.
3359
+ rows = rows.map(srcRow => {
3360
+ const dstRow = {};
3361
+ for (const column of columns) {
3362
+ dstRow[column] = srcRow[column];
3363
+ }
3364
+ return dstRow;
3365
+ });
3366
+ return Promise.resolve({
3367
+ rows,
3368
+ totalCount
3369
+ });
3370
+ } catch (e) {
3371
+ return Promise.reject(e);
3372
+ }
3373
+ }
3374
+ getTimeSeries(_ref7) {
3375
+ let {
3376
+ column,
3377
+ stepSize,
3378
+ operation,
3379
+ operationColumn,
3380
+ joinOperation,
3381
+ filterOwner
3382
+ } = _ref7;
3383
+ try {
3384
+ const _this6 = this;
3385
+ if (!_this6._features.length) {
3386
+ return Promise.resolve({
3387
+ rows: []
3388
+ });
3389
+ }
3390
+ const filteredFeatures = _this6._getFilteredFeatures(filterOwner);
3391
+ assertColumn(_this6._features, column, operationColumn);
3392
+ const rows = groupValuesByDateColumn({
3393
+ data: filteredFeatures,
3394
+ valuesColumns: normalizeColumns(operationColumn || column),
3395
+ keysColumn: column,
3396
+ groupType: stepSize,
3397
+ operation,
3398
+ joinOperation
3399
+ }) || [];
3400
+ return Promise.resolve({
3401
+ rows
3402
+ });
3403
+ } catch (e) {
3404
+ return Promise.reject(e);
3405
+ }
3406
+ }
3407
+ getRange(_ref8) {
3408
+ let {
3409
+ column,
3410
+ filterOwner
3411
+ } = _ref8;
3412
+ try {
3413
+ const _this7 = this;
3414
+ if (!_this7._features.length) {
3415
+ // TODO: Is this the only nullable response in the Widgets API? If so,
3416
+ // can we do something more consistent?
3417
+ return Promise.resolve(null);
3418
+ }
3419
+ assertColumn(_this7._features, column);
3420
+ const filteredFeatures = _this7._getFilteredFeatures(filterOwner);
3421
+ return Promise.resolve({
3422
+ min: aggregationFunctions.min(filteredFeatures, column),
3423
+ max: aggregationFunctions.max(filteredFeatures, column)
3424
+ });
3425
+ } catch (e) {
3426
+ return Promise.reject(e);
3427
+ }
3428
+ }
3429
+ /****************************************************************************
3430
+ * INTERNAL
3431
+ */
3432
+ _getFilteredFeatures(filterOwner) {
3433
+ return applyFilters(this._features, getApplicableFilters(filterOwner, this.props.filters), this.props.filtersLogicalOperator || 'and');
3434
+ }
3435
+ }
3436
+ function assertColumn(features) {
3437
+ // TODO(cleanup): Can drop support for multiple column shapes here?
3438
+ // Due to the multiple column shape, we normalise it as an array with normalizeColumns
3439
+ const columns = Array.from(new Set([].slice.call(arguments, 1).map(normalizeColumns).flat()));
3440
+ const featureKeys = Object.keys(features[0]);
3441
+ const invalidColumns = columns.filter(column => !featureKeys.includes(column));
3442
+ if (invalidColumns.length) {
3443
+ throw new InvalidColumnError(`Missing column(s): ${invalidColumns.join(', ')}`);
3444
+ }
3445
+ }
3446
+ function normalizeColumns(columns) {
3447
+ return Array.isArray(columns) ? columns : typeof columns === 'string' ? [columns] : [];
3448
+ }
3449
+
3450
+ // deck.gl
3451
+ // SPDX-License-Identifier: MIT
3452
+ // Copyright (c) vis.gl contributors
3453
+ /* eslint-disable camelcase */
3454
+ const h3QuerySource = function (options) {
3455
+ try {
3456
+ const {
3457
+ aggregationExp,
3458
+ aggregationResLevel = DEFAULT_AGGREGATION_RES_LEVEL_H3,
3459
+ sqlQuery,
3460
+ spatialDataColumn = 'h3',
3461
+ queryParameters,
3462
+ filters
3463
+ } = options;
3464
+ const urlParameters = {
3465
+ aggregationExp,
3466
+ spatialDataColumn,
3467
+ spatialDataType: 'h3',
3468
+ q: sqlQuery
3469
+ };
3470
+ if (aggregationResLevel) {
3471
+ urlParameters.aggregationResLevel = String(aggregationResLevel);
3472
+ }
3473
+ if (queryParameters) {
3474
+ urlParameters.queryParameters = queryParameters;
3475
+ }
3476
+ if (filters) {
3477
+ urlParameters.filters = filters;
3478
+ }
3479
+ return Promise.resolve(baseSource('query', options, urlParameters).then(result => ({
3480
+ ...result,
3481
+ widgetSource: new WidgetQuerySource({
3482
+ ...options,
3483
+ // NOTE: passing redundant spatialDataColumn here to apply the default value 'h3'
3484
+ spatialDataColumn,
3485
+ spatialDataType: 'h3'
3486
+ })
3487
+ })));
3488
+ } catch (e) {
3489
+ return Promise.reject(e);
3490
+ }
3491
+ };
3492
+
3493
+ // deck.gl
3494
+ // SPDX-License-Identifier: MIT
3495
+ // Copyright (c) vis.gl contributors
3496
+ /* eslint-disable camelcase */
3497
+ const h3TableSource = function (options) {
3498
+ try {
3499
+ const {
3500
+ aggregationExp,
3501
+ aggregationResLevel = DEFAULT_AGGREGATION_RES_LEVEL_H3,
3502
+ spatialDataColumn = 'h3',
3503
+ tableName,
3504
+ filters
3505
+ } = options;
3506
+ const urlParameters = {
3507
+ aggregationExp,
3508
+ name: tableName,
3509
+ spatialDataColumn,
3510
+ spatialDataType: 'h3'
3511
+ };
3512
+ if (aggregationResLevel) {
3513
+ urlParameters.aggregationResLevel = String(aggregationResLevel);
3514
+ }
3515
+ if (filters) {
3516
+ urlParameters.filters = filters;
3517
+ }
3518
+ return Promise.resolve(baseSource('table', options, urlParameters).then(result => ({
3519
+ ...result,
3520
+ widgetSource: new WidgetTableSource({
3521
+ ...options,
3522
+ // NOTE: passing redundant spatialDataColumn here to apply the default value 'h3'
3523
+ spatialDataColumn,
3524
+ spatialDataType: 'h3'
3525
+ })
3526
+ })));
3527
+ } catch (e) {
3528
+ return Promise.reject(e);
3529
+ }
3530
+ };
3531
+
3532
+ function getTileFormat(tilejson) {
3533
+ const tileParams = new URL(tilejson.tiles[0]).searchParams;
3534
+ return tileParams.get('formatTiles') === 'mvt' ? exports.TileFormat.MVT : exports.TileFormat.BINARY;
3535
+ }
3536
+
3537
+ // deck.gl
3538
+ // SPDX-License-Identifier: MIT
3539
+ // Copyright (c) vis.gl contributors
3540
+ const h3TilesetSource = function (options) {
3541
+ try {
3542
+ const {
3543
+ tableName,
3544
+ spatialDataColumn = 'h3'
3545
+ } = options;
3546
+ const urlParameters = {
3547
+ name: tableName
3548
+ };
3549
+ return Promise.resolve(baseSource('tileset', options, urlParameters).then(result => ({
3550
+ ...result,
3551
+ widgetSource: new WidgetTilesetSource({
3552
+ ...options,
3553
+ tileFormat: getTileFormat(result),
3554
+ spatialDataColumn,
3555
+ spatialDataType: 'h3'
3556
+ })
3557
+ })));
3558
+ } catch (e) {
3559
+ return Promise.reject(e);
3560
+ }
3561
+ };
3562
+
3563
+ // deck.gl
3564
+ // SPDX-License-Identifier: MIT
3565
+ // Copyright (c) vis.gl contributors
3566
+ const rasterSource = function (options) {
3567
+ try {
3568
+ const {
3569
+ tableName,
3570
+ filters
3571
+ } = options;
3572
+ const urlParameters = {
3573
+ name: tableName
3574
+ };
3575
+ if (filters) {
3576
+ urlParameters.filters = filters;
3577
+ }
3578
+ return Promise.resolve(baseSource('raster', options, urlParameters));
3579
+ } catch (e) {
3580
+ return Promise.reject(e);
3581
+ }
3582
+ };
3583
+
3584
+ // deck.gl
3585
+ // SPDX-License-Identifier: MIT
3586
+ // Copyright (c) vis.gl contributors
3587
+ /* eslint-disable camelcase */
3588
+ const quadbinQuerySource = function (options) {
3589
+ try {
3590
+ const {
3591
+ aggregationExp,
3592
+ aggregationResLevel = DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN,
3593
+ sqlQuery,
3594
+ spatialDataColumn = 'quadbin',
3595
+ queryParameters,
3596
+ filters
3597
+ } = options;
3598
+ const urlParameters = {
3599
+ aggregationExp,
3600
+ q: sqlQuery,
3601
+ spatialDataColumn,
3602
+ spatialDataType: 'quadbin'
3603
+ };
3604
+ if (aggregationResLevel) {
3605
+ urlParameters.aggregationResLevel = String(aggregationResLevel);
3606
+ }
3607
+ if (queryParameters) {
3608
+ urlParameters.queryParameters = queryParameters;
3609
+ }
3610
+ if (filters) {
3611
+ urlParameters.filters = filters;
3612
+ }
3613
+ return Promise.resolve(baseSource('query', options, urlParameters).then(result => ({
3614
+ ...result,
3615
+ widgetSource: new WidgetQuerySource({
3616
+ ...options,
3617
+ // NOTE: passing redundant spatialDataColumn here to apply the default value 'quadbin'
3618
+ spatialDataColumn,
3619
+ spatialDataType: 'quadbin'
3620
+ })
3621
+ })));
3622
+ } catch (e) {
3623
+ return Promise.reject(e);
3624
+ }
3625
+ };
3626
+
3627
+ // deck.gl
3628
+ // SPDX-License-Identifier: MIT
3629
+ // Copyright (c) vis.gl contributors
3630
+ /* eslint-disable camelcase */
3631
+ const quadbinTableSource = function (options) {
3632
+ try {
3633
+ const {
3634
+ aggregationExp,
3635
+ aggregationResLevel = DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN,
3636
+ spatialDataColumn = 'quadbin',
3637
+ tableName,
3638
+ filters
1574
3639
  } = options;
1575
3640
  const urlParameters = {
1576
3641
  aggregationExp,
@@ -1586,7 +3651,12 @@ const quadbinTableSource = function (options) {
1586
3651
  }
1587
3652
  return Promise.resolve(baseSource('table', options, urlParameters).then(result => ({
1588
3653
  ...result,
1589
- widgetSource: new WidgetTableSource(options)
3654
+ widgetSource: new WidgetTableSource({
3655
+ ...options,
3656
+ // NOTE: passing redundant spatialDataColumn here to apply the default value 'quadbin'
3657
+ spatialDataColumn,
3658
+ spatialDataType: 'quadbin'
3659
+ })
1590
3660
  })));
1591
3661
  } catch (e) {
1592
3662
  return Promise.reject(e);
@@ -1594,27 +3664,41 @@ const quadbinTableSource = function (options) {
1594
3664
  };
1595
3665
 
1596
3666
  // deck.gl
3667
+ // SPDX-License-Identifier: MIT
3668
+ // Copyright (c) vis.gl contributors
1597
3669
  const quadbinTilesetSource = function (options) {
1598
3670
  try {
1599
3671
  const {
1600
- tableName
3672
+ tableName,
3673
+ spatialDataColumn = 'quadbin'
1601
3674
  } = options;
1602
3675
  const urlParameters = {
1603
3676
  name: tableName
1604
3677
  };
1605
- return Promise.resolve(baseSource('tileset', options, urlParameters));
3678
+ return Promise.resolve(baseSource('tileset', options, urlParameters).then(result => ({
3679
+ ...result,
3680
+ widgetSource: new WidgetTilesetSource({
3681
+ ...options,
3682
+ tileFormat: getTileFormat(result),
3683
+ spatialDataColumn,
3684
+ spatialDataType: 'quadbin'
3685
+ })
3686
+ })));
1606
3687
  } catch (e) {
1607
3688
  return Promise.reject(e);
1608
3689
  }
1609
3690
  };
1610
3691
 
1611
3692
  // deck.gl
3693
+ // SPDX-License-Identifier: MIT
3694
+ // Copyright (c) vis.gl contributors
3695
+ /* eslint-disable camelcase */
1612
3696
  const vectorQuerySource = function (options) {
1613
3697
  try {
1614
3698
  const {
1615
3699
  columns,
1616
3700
  filters,
1617
- spatialDataColumn = 'geom',
3701
+ spatialDataColumn = DEFAULT_GEO_COLUMN,
1618
3702
  sqlQuery,
1619
3703
  tileResolution = DEFAULT_TILE_RESOLUTION,
1620
3704
  queryParameters,
@@ -1640,7 +3724,11 @@ const vectorQuerySource = function (options) {
1640
3724
  }
1641
3725
  return Promise.resolve(baseSource('query', options, urlParameters).then(result => ({
1642
3726
  ...result,
1643
- widgetSource: new WidgetQuerySource(options)
3727
+ widgetSource: new WidgetQuerySource({
3728
+ ...options,
3729
+ spatialDataColumn,
3730
+ spatialDataType: 'geo'
3731
+ })
1644
3732
  })));
1645
3733
  } catch (e) {
1646
3734
  return Promise.reject(e);
@@ -1648,12 +3736,15 @@ const vectorQuerySource = function (options) {
1648
3736
  };
1649
3737
 
1650
3738
  // deck.gl
3739
+ // SPDX-License-Identifier: MIT
3740
+ // Copyright (c) vis.gl contributors
3741
+ /* eslint-disable camelcase */
1651
3742
  const vectorTableSource = function (options) {
1652
3743
  try {
1653
3744
  const {
1654
3745
  columns,
1655
3746
  filters,
1656
- spatialDataColumn = 'geom',
3747
+ spatialDataColumn = DEFAULT_GEO_COLUMN,
1657
3748
  tableName,
1658
3749
  tileResolution = DEFAULT_TILE_RESOLUTION,
1659
3750
  aggregationExp
@@ -1675,7 +3766,11 @@ const vectorTableSource = function (options) {
1675
3766
  }
1676
3767
  return Promise.resolve(baseSource('table', options, urlParameters).then(result => ({
1677
3768
  ...result,
1678
- widgetSource: new WidgetTableSource(options)
3769
+ widgetSource: new WidgetTableSource({
3770
+ ...options,
3771
+ spatialDataColumn,
3772
+ spatialDataType: 'geo'
3773
+ })
1679
3774
  })));
1680
3775
  } catch (e) {
1681
3776
  return Promise.reject(e);
@@ -1683,21 +3778,34 @@ const vectorTableSource = function (options) {
1683
3778
  };
1684
3779
 
1685
3780
  // deck.gl
3781
+ // SPDX-License-Identifier: MIT
3782
+ // Copyright (c) vis.gl contributors
1686
3783
  const vectorTilesetSource = function (options) {
1687
3784
  try {
1688
3785
  const {
1689
- tableName
3786
+ tableName,
3787
+ spatialDataColumn = DEFAULT_GEO_COLUMN
1690
3788
  } = options;
1691
3789
  const urlParameters = {
1692
3790
  name: tableName
1693
3791
  };
1694
- return Promise.resolve(baseSource('tileset', options, urlParameters));
3792
+ return Promise.resolve(baseSource('tileset', options, urlParameters).then(result => ({
3793
+ ...result,
3794
+ widgetSource: new WidgetTilesetSource({
3795
+ ...options,
3796
+ tileFormat: getTileFormat(result),
3797
+ spatialDataColumn,
3798
+ spatialDataType: 'geo'
3799
+ })
3800
+ })));
1695
3801
  } catch (e) {
1696
3802
  return Promise.reject(e);
1697
3803
  }
1698
3804
  };
1699
3805
 
1700
3806
  // deck.gl
3807
+ // SPDX-License-Identifier: MIT
3808
+ // Copyright (c) vis.gl contributors
1701
3809
  const query = function (options) {
1702
3810
  try {
1703
3811
  const {
@@ -1748,24 +3856,38 @@ const query = function (options) {
1748
3856
 
1749
3857
  exports.CartoAPIError = CartoAPIError;
1750
3858
  exports.DEFAULT_API_BASE_URL = DEFAULT_API_BASE_URL;
3859
+ exports.FEATURE_GEOM_PROPERTY = FEATURE_GEOM_PROPERTY;
1751
3860
  exports.SOURCE_DEFAULTS = SOURCE_DEFAULTS;
1752
- exports.WidgetBaseSource = WidgetBaseSource;
1753
3861
  exports.WidgetQuerySource = WidgetQuerySource;
3862
+ exports.WidgetRemoteSource = WidgetRemoteSource;
1754
3863
  exports.WidgetTableSource = WidgetTableSource;
3864
+ exports.WidgetTilesetSource = WidgetTilesetSource;
1755
3865
  exports.addFilter = addFilter;
3866
+ exports.aggregate = aggregate;
3867
+ exports.aggregationFunctions = aggregationFunctions;
3868
+ exports.applyFilters = applyFilters;
3869
+ exports.applySorting = applySorting;
1756
3870
  exports.boundaryQuerySource = boundaryQuerySource;
1757
3871
  exports.boundaryTableSource = boundaryTableSource;
3872
+ exports.buildBinaryFeatureFilter = buildBinaryFeatureFilter;
3873
+ exports.buildFeatureFilter = buildFeatureFilter;
1758
3874
  exports.buildPublicMapUrl = buildPublicMapUrl;
1759
3875
  exports.buildStatsUrl = buildStatsUrl;
1760
3876
  exports.clearFilters = clearFilters;
1761
3877
  exports.createPolygonSpatialFilter = createPolygonSpatialFilter;
1762
3878
  exports.createViewportSpatialFilter = createViewportSpatialFilter;
3879
+ exports.filterFunctions = filterFunctions;
3880
+ exports.geojsonFeatures = geojsonFeatures;
1763
3881
  exports.getClient = getClient;
1764
3882
  exports.getFilter = getFilter;
3883
+ exports.groupValuesByColumn = groupValuesByColumn;
3884
+ exports.groupValuesByDateColumn = groupValuesByDateColumn;
1765
3885
  exports.h3QuerySource = h3QuerySource;
1766
3886
  exports.h3TableSource = h3TableSource;
1767
3887
  exports.h3TilesetSource = h3TilesetSource;
1768
3888
  exports.hasFilter = hasFilter;
3889
+ exports.histogram = histogram;
3890
+ exports.makeIntervalComplete = makeIntervalComplete;
1769
3891
  exports.quadbinQuerySource = quadbinQuerySource;
1770
3892
  exports.quadbinTableSource = quadbinTableSource;
1771
3893
  exports.quadbinTilesetSource = quadbinTilesetSource;
@@ -1773,7 +3895,12 @@ exports.query = query;
1773
3895
  exports.rasterSource = rasterSource;
1774
3896
  exports.removeFilter = removeFilter;
1775
3897
  exports.requestWithParameters = requestWithParameters;
3898
+ exports.scatterPlot = scatterPlot;
1776
3899
  exports.setClient = setClient;
3900
+ exports.tileFeatures = tileFeatures;
3901
+ exports.tileFeaturesGeometries = tileFeaturesGeometries;
3902
+ exports.tileFeaturesSpatialIndex = tileFeaturesSpatialIndex;
3903
+ exports.transformToTileCoords = transformToTileCoords;
1777
3904
  exports.vectorQuerySource = vectorQuerySource;
1778
3905
  exports.vectorTableSource = vectorTableSource;
1779
3906
  exports.vectorTilesetSource = vectorTilesetSource;