@carto/api-client 0.4.6-0 → 0.4.6

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 (81) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/build/api-client.cjs +208 -2167
  3. package/build/api-client.cjs.map +1 -1
  4. package/build/api-client.modern.js +208 -2040
  5. package/build/api-client.modern.js.map +1 -1
  6. package/build/constants.d.ts +0 -22
  7. package/build/index.d.ts +1 -4
  8. package/build/models/index.d.ts +1 -1
  9. package/build/sources/h3-tileset-source.d.ts +1 -2
  10. package/build/sources/index.d.ts +1 -1
  11. package/build/sources/quadbin-tileset-source.d.ts +1 -2
  12. package/build/sources/vector-tileset-source.d.ts +1 -2
  13. package/build/spatial-index.d.ts +7 -1
  14. package/build/types-internal.d.ts +0 -4
  15. package/build/types.d.ts +1 -61
  16. package/build/widget-sources/index.d.ts +1 -3
  17. package/build/widget-sources/types.d.ts +22 -31
  18. package/build/widget-sources/{widget-source.d.ts → widget-base-source.d.ts} +38 -13
  19. package/build/widget-sources/widget-query-source.d.ts +2 -2
  20. package/build/widget-sources/widget-table-source.d.ts +2 -2
  21. package/package.json +11 -14
  22. package/src/constants.ts +0 -25
  23. package/src/index.ts +1 -5
  24. package/src/models/index.ts +1 -1
  25. package/src/sources/h3-tileset-source.ts +6 -18
  26. package/src/sources/index.ts +1 -1
  27. package/src/sources/quadbin-tileset-source.ts +6 -18
  28. package/src/sources/raster-source.ts +0 -1
  29. package/src/sources/vector-query-source.ts +2 -5
  30. package/src/sources/vector-table-source.ts +2 -5
  31. package/src/sources/vector-tileset-source.ts +6 -19
  32. package/src/spatial-index.ts +8 -5
  33. package/src/types-internal.ts +0 -6
  34. package/src/types.ts +2 -60
  35. package/src/widget-sources/index.ts +1 -3
  36. package/src/widget-sources/types.ts +22 -32
  37. package/src/widget-sources/{widget-remote-source.ts → widget-base-source.ts} +147 -12
  38. package/src/widget-sources/widget-query-source.ts +3 -6
  39. package/src/widget-sources/widget-table-source.ts +3 -6
  40. package/build/filters/Filter.d.ts +0 -13
  41. package/build/filters/FilterTypes.d.ts +0 -3
  42. package/build/filters/geosjonFeatures.d.ts +0 -8
  43. package/build/filters/index.d.ts +0 -6
  44. package/build/filters/tileFeatures.d.ts +0 -20
  45. package/build/filters/tileFeaturesGeometries.d.ts +0 -13
  46. package/build/filters/tileFeaturesSpatialIndex.d.ts +0 -10
  47. package/build/operations/aggregation.d.ts +0 -8
  48. package/build/operations/applySorting.d.ts +0 -20
  49. package/build/operations/groupBy.d.ts +0 -15
  50. package/build/operations/groupByDate.d.ts +0 -11
  51. package/build/operations/histogram.d.ts +0 -13
  52. package/build/operations/index.d.ts +0 -6
  53. package/build/operations/scatterPlot.d.ts +0 -14
  54. package/build/utils/dateUtils.d.ts +0 -10
  55. package/build/utils/getTileFormat.d.ts +0 -3
  56. package/build/utils/makeIntervalComplete.d.ts +0 -2
  57. package/build/utils/transformTileCoordsToWGS84.d.ts +0 -8
  58. package/build/utils/transformToTileCoords.d.ts +0 -9
  59. package/build/widget-sources/widget-remote-source.d.ts +0 -18
  60. package/build/widget-sources/widget-tileset-source.d.ts +0 -76
  61. package/src/filters/Filter.ts +0 -169
  62. package/src/filters/FilterTypes.ts +0 -109
  63. package/src/filters/geosjonFeatures.ts +0 -32
  64. package/src/filters/index.ts +0 -6
  65. package/src/filters/tileFeatures.ts +0 -56
  66. package/src/filters/tileFeaturesGeometries.ts +0 -444
  67. package/src/filters/tileFeaturesSpatialIndex.ts +0 -119
  68. package/src/operations/aggregation.ts +0 -154
  69. package/src/operations/applySorting.ts +0 -109
  70. package/src/operations/groupBy.ts +0 -59
  71. package/src/operations/groupByDate.ts +0 -98
  72. package/src/operations/histogram.ts +0 -66
  73. package/src/operations/index.ts +0 -6
  74. package/src/operations/scatterPlot.ts +0 -50
  75. package/src/utils/dateUtils.ts +0 -28
  76. package/src/utils/getTileFormat.ts +0 -9
  77. package/src/utils/makeIntervalComplete.ts +0 -17
  78. package/src/utils/transformTileCoordsToWGS84.ts +0 -77
  79. package/src/utils/transformToTileCoords.ts +0 -85
  80. package/src/widget-sources/widget-source.ts +0 -160
  81. package/src/widget-sources/widget-tileset-source.ts +0 -407
@@ -3,10 +3,6 @@ import bboxPolygon from '@turf/bbox-polygon';
3
3
  import union from '@turf/union';
4
4
  import { getType } from '@turf/invariant';
5
5
  import { featureCollection, feature, polygon, multiPolygon } from '@turf/helpers';
6
- import intersects from '@turf/boolean-intersects';
7
- import booleanWithin from '@turf/boolean-within';
8
- import intersect from '@turf/intersect';
9
- import { getResolution as getResolution$2, polygonToCells } from 'h3-js';
10
6
 
11
7
  /**
12
8
  * @internal
@@ -65,31 +61,6 @@ var ApiVersion;
65
61
  })(ApiVersion || (ApiVersion = {}));
66
62
  /** @internalRemarks Source: @carto/constants, @deck.gl/carto */
67
63
  const DEFAULT_API_BASE_URL = 'https://gcp-us-east1.api.carto.com';
68
- /** @internalRemarks Source: @carto/react-core */
69
- var TileFormat;
70
- (function (TileFormat) {
71
- TileFormat["MVT"] = "mvt";
72
- TileFormat["JSON"] = "json";
73
- TileFormat["GEOJSON"] = "geojson";
74
- TileFormat["BINARY"] = "binary";
75
- })(TileFormat || (TileFormat = {}));
76
- /** @internalRemarks Source: @carto/react-core */
77
- var SpatialIndex;
78
- (function (SpatialIndex) {
79
- SpatialIndex["H3"] = "h3";
80
- SpatialIndex["S2"] = "s2";
81
- SpatialIndex["QUADBIN"] = "quadbin";
82
- })(SpatialIndex || (SpatialIndex = {}));
83
- /** @internalRemarks Source: @carto/react-core */
84
- var Provider;
85
- (function (Provider) {
86
- Provider["BIGQUERY"] = "bigquery";
87
- Provider["REDSHIFT"] = "redshift";
88
- Provider["POSTGRES"] = "postgres";
89
- Provider["SNOWFLAKE"] = "snowflake";
90
- Provider["DATABRICKS"] = "databricks";
91
- Provider["DATABRICKS_REST"] = "databricksRest";
92
- })(Provider || (Provider = {}));
93
64
 
94
65
  const FILTER_TYPES = new Set(Object.values(FilterType));
95
66
  const isFilterType = type => FILTER_TYPES.has(type);
@@ -132,7 +103,7 @@ function normalizeObjectKeys(el) {
132
103
  }, {});
133
104
  }
134
105
  /** @internalRemarks Source: @carto/react-core */
135
- function assert$1(condition, message) {
106
+ function assert(condition, message) {
136
107
  if (!condition) {
137
108
  throw new Error(message);
138
109
  }
@@ -635,7 +606,7 @@ function excludeURLParameters(baseUrlString, parameters) {
635
606
  return baseUrl.toString();
636
607
  }
637
608
 
638
- const _excluded$2 = ["accessToken", "connectionName", "cache"];
609
+ const _excluded$1 = ["accessToken", "connectionName", "cache"];
639
610
  const SOURCE_DEFAULTS = {
640
611
  apiBaseUrl: DEFAULT_API_BASE_URL,
641
612
  clientId: getClient(),
@@ -649,7 +620,7 @@ async function baseSource(endpoint, options, urlParameters) {
649
620
  connectionName,
650
621
  cache
651
622
  } = options,
652
- optionalOptions = _objectWithoutPropertiesLoose(options, _excluded$2);
623
+ optionalOptions = _objectWithoutPropertiesLoose(options, _excluded$1);
653
624
  const mergedOptions = _extends({}, SOURCE_DEFAULTS, {
654
625
  accessToken,
655
626
  connectionName,
@@ -764,91 +735,6 @@ const boundaryTableSource = async function boundaryTableSource(options) {
764
735
  return baseSource('boundary', options, urlParameters);
765
736
  };
766
737
 
767
- const DEFAULT_TILE_SIZE = 512;
768
- const QUADBIN_ZOOM_MAX_OFFSET = 4;
769
- function getSpatialFiltersResolution(source, viewState) {
770
- var _source$dataResolutio, _source$aggregationRe;
771
- const dataResolution = (_source$dataResolutio = source.dataResolution) != null ? _source$dataResolutio : Number.MAX_VALUE;
772
- const aggregationResLevel = (_source$aggregationRe = source.aggregationResLevel) != null ? _source$aggregationRe : source.spatialDataType === 'h3' ? DEFAULT_AGGREGATION_RES_LEVEL_H3 : DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN;
773
- const aggregationResLevelOffset = Math.max(0, Math.floor(aggregationResLevel));
774
- const currentZoomInt = Math.ceil(viewState.zoom);
775
- if (source.spatialDataType === 'h3') {
776
- var _maxH3SpatialFiltersR, _maxH3SpatialFiltersR2;
777
- const tileSize = DEFAULT_TILE_SIZE;
778
- const maxResolutionForZoom = (_maxH3SpatialFiltersR = (_maxH3SpatialFiltersR2 = maxH3SpatialFiltersResolutions.find(([zoom]) => zoom === currentZoomInt)) == null ? void 0 : _maxH3SpatialFiltersR2[1]) != null ? _maxH3SpatialFiltersR : Math.max(0, currentZoomInt - 3);
779
- const maxSpatialFiltersResolution = maxResolutionForZoom ? Math.min(dataResolution, maxResolutionForZoom) : dataResolution;
780
- const hexagonResolution = getHexagonResolution(viewState, tileSize) + aggregationResLevelOffset;
781
- return Math.min(hexagonResolution, maxSpatialFiltersResolution);
782
- }
783
- if (source.spatialDataType === 'quadbin') {
784
- const maxResolutionForZoom = currentZoomInt + QUADBIN_ZOOM_MAX_OFFSET;
785
- const maxSpatialFiltersResolution = Math.min(dataResolution, maxResolutionForZoom);
786
- const quadsResolution = Math.floor(viewState.zoom) + aggregationResLevelOffset;
787
- return Math.min(quadsResolution, maxSpatialFiltersResolution);
788
- }
789
- return undefined;
790
- }
791
- 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]];
792
- // stolen from https://github.com/visgl/deck.gl/blob/master/modules/carto/src/layers/h3-tileset-2d.ts
793
- // Relative scale factor (0 = no biasing, 2 = a few hexagons cover view)
794
- const BIAS = 2;
795
- // Resolution conversion function. Takes a WebMercatorViewport and returns
796
- // a H3 resolution such that the screen space size of the hexagons is
797
- // similar
798
- function getHexagonResolution(viewport, tileSize) {
799
- // Difference in given tile size compared to deck's internal 512px tile size,
800
- // expressed as an offset to the viewport zoom.
801
- const zoomOffset = Math.log2(tileSize / DEFAULT_TILE_SIZE);
802
- const hexagonScaleFactor = 2 / 3 * (viewport.zoom - zoomOffset);
803
- const latitudeScaleFactor = Math.log(1 / Math.cos(Math.PI * viewport.latitude / 180));
804
- // Clip and bias
805
- return Math.max(0, Math.floor(hexagonScaleFactor + latitudeScaleFactor - BIAS));
806
- }
807
-
808
- /**
809
- * Source for Widget API requests on a data source defined by a SQL query.
810
- *
811
- * Abstract class. Use {@link WidgetQuerySource} or {@link WidgetTableSource}.
812
- */
813
- class WidgetSource {
814
- constructor(props) {
815
- this.props = void 0;
816
- this.props = _extends({}, WidgetSource.defaultProps, props);
817
- }
818
- _getModelSource(owner) {
819
- const props = this.props;
820
- return {
821
- apiVersion: props.apiVersion,
822
- apiBaseUrl: props.apiBaseUrl,
823
- clientId: props.clientId,
824
- accessToken: props.accessToken,
825
- connectionName: props.connectionName,
826
- filters: getApplicableFilters(owner, props.filters),
827
- filtersLogicalOperator: props.filtersLogicalOperator,
828
- spatialDataType: props.spatialDataType,
829
- spatialDataColumn: props.spatialDataColumn,
830
- dataResolution: props.dataResolution
831
- };
832
- }
833
- _getSpatialFiltersResolution(source, spatialFilter, referenceViewState) {
834
- // spatialFiltersResolution applies only to spatial index sources.
835
- if (!spatialFilter || source.spatialDataType === 'geo') {
836
- return;
837
- }
838
- if (!referenceViewState) {
839
- throw new Error('Missing required option, "spatialIndexReferenceViewState".');
840
- }
841
- return getSpatialFiltersResolution(source, referenceViewState);
842
- }
843
- }
844
- WidgetSource.defaultProps = {
845
- apiVersion: ApiVersion.V3,
846
- apiBaseUrl: DEFAULT_API_BASE_URL,
847
- clientId: getClient(),
848
- filters: {},
849
- filtersLogicalOperator: 'and'
850
- };
851
-
852
738
  /**
853
739
  * Return more descriptive error from API
854
740
  * @internalRemarks Source: @carto/react-api
@@ -922,10 +808,10 @@ const REQUEST_GET_MAX_URL_LENGTH = 2048;
922
808
  * @internalRemarks Source: @carto/react-api
923
809
  */
924
810
  function executeModel(props) {
925
- assert$1(props.source, 'executeModel: missing source');
926
- assert$1(props.model, 'executeModel: missing model');
927
- assert$1(props.params, 'executeModel: missing params');
928
- assert$1(AVAILABLE_MODELS.includes(props.model), `executeModel: model provided isn't valid. Available models: ${AVAILABLE_MODELS.join(', ')}`);
811
+ assert(props.source, 'executeModel: missing source');
812
+ assert(props.model, 'executeModel: missing model');
813
+ assert(props.params, 'executeModel: missing params');
814
+ assert(AVAILABLE_MODELS.includes(props.model), `executeModel: model provided isn't valid. Available models: ${AVAILABLE_MODELS.join(', ')}`);
929
815
  const {
930
816
  model,
931
817
  source,
@@ -940,10 +826,10 @@ function executeModel(props) {
940
826
  connectionName,
941
827
  clientId
942
828
  } = source;
943
- assert$1(apiBaseUrl, 'executeModel: missing apiBaseUrl');
944
- assert$1(accessToken, 'executeModel: missing accessToken');
945
- assert$1(apiVersion === V3, 'executeModel: SQL Model API requires CARTO 3+');
946
- assert$1(type !== 'tileset', 'executeModel: Tilesets not supported');
829
+ assert(apiBaseUrl, 'executeModel: missing apiBaseUrl');
830
+ assert(accessToken, 'executeModel: missing accessToken');
831
+ assert(apiVersion === V3, 'executeModel: SQL Model API requires CARTO 3+');
832
+ assert(type !== 'tileset', 'executeModel: Tilesets not supported');
947
833
  let url = `${apiBaseUrl}/v3/sql/${connectionName}/model/${model}`;
948
834
  const {
949
835
  data,
@@ -1013,7 +899,51 @@ function objectToURLSearchParams(object) {
1013
899
  return params;
1014
900
  }
1015
901
 
1016
- const _excluded$1 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
902
+ const DEFAULT_TILE_SIZE = 512;
903
+ const QUADBIN_ZOOM_MAX_OFFSET = 4;
904
+ function getSpatialFiltersResolution(source, viewState) {
905
+ var _source$dataResolutio, _source$aggregationRe;
906
+ const dataResolution = (_source$dataResolutio = source.dataResolution) != null ? _source$dataResolutio : Number.MAX_VALUE;
907
+ const aggregationResLevel = (_source$aggregationRe = source.aggregationResLevel) != null ? _source$aggregationRe : source.spatialDataType === 'h3' ? DEFAULT_AGGREGATION_RES_LEVEL_H3 : DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN;
908
+ const aggregationResLevelOffset = Math.max(0, Math.floor(aggregationResLevel));
909
+ const currentZoomInt = Math.ceil(viewState.zoom);
910
+ if (source.spatialDataType === 'h3') {
911
+ var _maxH3SpatialFiltersR, _maxH3SpatialFiltersR2;
912
+ const tileSize = DEFAULT_TILE_SIZE;
913
+ const maxResolutionForZoom = (_maxH3SpatialFiltersR = (_maxH3SpatialFiltersR2 = maxH3SpatialFiltersResolutions.find(([zoom]) => zoom === currentZoomInt)) == null ? void 0 : _maxH3SpatialFiltersR2[1]) != null ? _maxH3SpatialFiltersR : Math.max(0, currentZoomInt - 3);
914
+ const maxSpatialFiltersResolution = maxResolutionForZoom ? Math.min(dataResolution, maxResolutionForZoom) : dataResolution;
915
+ const hexagonResolution = _getHexagonResolution(viewState, tileSize) + aggregationResLevelOffset;
916
+ return Math.min(hexagonResolution, maxSpatialFiltersResolution);
917
+ }
918
+ if (source.spatialDataType === 'quadbin') {
919
+ const maxResolutionForZoom = currentZoomInt + QUADBIN_ZOOM_MAX_OFFSET;
920
+ const maxSpatialFiltersResolution = Math.min(dataResolution, maxResolutionForZoom);
921
+ const quadsResolution = Math.floor(viewState.zoom) + aggregationResLevelOffset;
922
+ return Math.min(quadsResolution, maxSpatialFiltersResolution);
923
+ }
924
+ return undefined;
925
+ }
926
+ 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]];
927
+ // stolen from https://github.com/visgl/deck.gl/blob/master/modules/carto/src/layers/h3-tileset-2d.ts
928
+ // Relative scale factor (0 = no biasing, 2 = a few hexagons cover view)
929
+ const BIAS = 2;
930
+ /**
931
+ * Resolution conversion function. Takes a WebMercatorViewport and returns
932
+ * a H3 resolution such that the screen space size of the hexagons is
933
+ * "similar" to the given tileSize on screen. Intended for use with deck.gl.
934
+ * @internal
935
+ */
936
+ function _getHexagonResolution(viewport, tileSize) {
937
+ // Difference in given tile size compared to deck's internal 512px tile size,
938
+ // expressed as an offset to the viewport zoom.
939
+ const zoomOffset = Math.log2(tileSize / DEFAULT_TILE_SIZE);
940
+ const hexagonScaleFactor = 2 / 3 * (viewport.zoom - zoomOffset);
941
+ const latitudeScaleFactor = Math.log(1 / Math.cos(Math.PI * viewport.latitude / 180));
942
+ // Clip and bias
943
+ return Math.max(0, Math.floor(hexagonScaleFactor + latitudeScaleFactor - BIAS));
944
+ }
945
+
946
+ const _excluded = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
1017
947
  _excluded2 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
1018
948
  _excluded3 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController", "operationExp"],
1019
949
  _excluded4 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
@@ -1022,11 +952,47 @@ const _excluded$1 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spat
1022
952
  _excluded7 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
1023
953
  _excluded8 = ["filterOwner", "abortController", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState"];
1024
954
  /**
1025
- * Source for Widget API requests.
955
+ * Source for Widget API requests on a data source defined by a SQL query.
1026
956
  *
1027
957
  * Abstract class. Use {@link WidgetQuerySource} or {@link WidgetTableSource}.
1028
958
  */
1029
- class WidgetRemoteSource extends WidgetSource {
959
+ class WidgetBaseSource {
960
+ constructor(props) {
961
+ this.props = void 0;
962
+ this.props = _extends({}, WidgetBaseSource.defaultProps, props);
963
+ }
964
+ _getModelSource(owner) {
965
+ const props = this.props;
966
+ return {
967
+ apiVersion: props.apiVersion,
968
+ apiBaseUrl: props.apiBaseUrl,
969
+ clientId: props.clientId,
970
+ accessToken: props.accessToken,
971
+ connectionName: props.connectionName,
972
+ filters: getApplicableFilters(owner, props.filters),
973
+ filtersLogicalOperator: props.filtersLogicalOperator,
974
+ spatialDataType: props.spatialDataType,
975
+ spatialDataColumn: props.spatialDataColumn,
976
+ dataResolution: props.dataResolution
977
+ };
978
+ }
979
+ _getSpatialFiltersResolution(source, spatialFilter, referenceViewState) {
980
+ // spatialFiltersResolution applies only to spatial index sources.
981
+ if (!spatialFilter || source.spatialDataType === 'geo') {
982
+ return;
983
+ }
984
+ if (!referenceViewState) {
985
+ throw new Error('Missing required option, "spatialIndexReferenceViewState".');
986
+ }
987
+ return getSpatialFiltersResolution(source, referenceViewState);
988
+ }
989
+ /****************************************************************************
990
+ * CATEGORIES
991
+ */
992
+ /**
993
+ * Returns a list of labeled datapoints for categorical data. Suitable for
994
+ * charts including grouped bar charts, pie charts, and tree charts.
995
+ */
1030
996
  async getCategories(options) {
1031
997
  const {
1032
998
  filterOwner,
@@ -1035,7 +1001,7 @@ class WidgetRemoteSource extends WidgetSource {
1035
1001
  spatialIndexReferenceViewState,
1036
1002
  abortController
1037
1003
  } = options,
1038
- params = _objectWithoutPropertiesLoose(options, _excluded$1);
1004
+ params = _objectWithoutPropertiesLoose(options, _excluded);
1039
1005
  const {
1040
1006
  column,
1041
1007
  operation,
@@ -1060,6 +1026,17 @@ class WidgetRemoteSource extends WidgetSource {
1060
1026
  }
1061
1027
  }).then(res => normalizeObjectKeys(res.rows));
1062
1028
  }
1029
+ /****************************************************************************
1030
+ * FEATURES
1031
+ */
1032
+ /**
1033
+ * Given a list of feature IDs (as found in `_carto_feature_id`) returns all
1034
+ * matching features. In datasets containing features with duplicate geometries,
1035
+ * feature IDs may be duplicated (IDs are a hash of geometry) and so more
1036
+ * results may be returned than IDs in the request.
1037
+ * @internal
1038
+ * @experimental
1039
+ */
1063
1040
  async getFeatures(options) {
1064
1041
  const {
1065
1042
  filterOwner,
@@ -1104,6 +1081,13 @@ class WidgetRemoteSource extends WidgetSource {
1104
1081
  rows
1105
1082
  }));
1106
1083
  }
1084
+ /****************************************************************************
1085
+ * FORMULA
1086
+ */
1087
+ /**
1088
+ * Returns a scalar numerical statistic over all matching data. Suitable
1089
+ * for 'headline' or 'scorecard' figures such as counts and sums.
1090
+ */
1107
1091
  async getFormula(options) {
1108
1092
  const {
1109
1093
  filterOwner,
@@ -1129,7 +1113,7 @@ class WidgetRemoteSource extends WidgetSource {
1129
1113
  }),
1130
1114
  params: {
1131
1115
  column: column != null ? column : '*',
1132
- operation: operation != null ? operation : 'count',
1116
+ operation,
1133
1117
  operationExp
1134
1118
  },
1135
1119
  opts: {
@@ -1137,6 +1121,13 @@ class WidgetRemoteSource extends WidgetSource {
1137
1121
  }
1138
1122
  }).then(res => normalizeObjectKeys(res.rows[0]));
1139
1123
  }
1124
+ /****************************************************************************
1125
+ * HISTOGRAM
1126
+ */
1127
+ /**
1128
+ * Returns a list of labeled datapoints for 'bins' of data defined as ticks
1129
+ * over a numerical range. Suitable for histogram charts.
1130
+ */
1140
1131
  async getHistogram(options) {
1141
1132
  const {
1142
1133
  filterOwner,
@@ -1181,6 +1172,14 @@ class WidgetRemoteSource extends WidgetSource {
1181
1172
  }
1182
1173
  return [];
1183
1174
  }
1175
+ /****************************************************************************
1176
+ * RANGE
1177
+ */
1178
+ /**
1179
+ * Returns a range (min and max) for a numerical column of matching rows.
1180
+ * Suitable for displaying certain 'headline' or 'scorecard' statistics,
1181
+ * or rendering a range slider UI for filtering.
1182
+ */
1184
1183
  async getRange(options) {
1185
1184
  const {
1186
1185
  filterOwner,
@@ -1210,6 +1209,13 @@ class WidgetRemoteSource extends WidgetSource {
1210
1209
  }
1211
1210
  }).then(res => normalizeObjectKeys(res.rows[0]));
1212
1211
  }
1212
+ /****************************************************************************
1213
+ * SCATTER
1214
+ */
1215
+ /**
1216
+ * Returns a list of bivariate datapoints defined as numerical 'x' and 'y'
1217
+ * values. Suitable for rendering scatter plots.
1218
+ */
1213
1219
  async getScatter(options) {
1214
1220
  const {
1215
1221
  filterOwner,
@@ -1251,6 +1257,13 @@ class WidgetRemoteSource extends WidgetSource {
1251
1257
  y
1252
1258
  }) => [x, y]));
1253
1259
  }
1260
+ /****************************************************************************
1261
+ * TABLE
1262
+ */
1263
+ /**
1264
+ * Returns a list of arbitrary data rows, with support for pagination and
1265
+ * sorting. Suitable for displaying tables and lists.
1266
+ */
1254
1267
  async getTable(options) {
1255
1268
  const {
1256
1269
  filterOwner,
@@ -1295,6 +1308,13 @@ class WidgetRemoteSource extends WidgetSource {
1295
1308
  };
1296
1309
  });
1297
1310
  }
1311
+ /****************************************************************************
1312
+ * TIME SERIES
1313
+ */
1314
+ /**
1315
+ * Returns a series of labeled numerical values, grouped into equally-sized
1316
+ * time intervals. Suitable for rendering time series charts.
1317
+ */
1298
1318
  async getTimeSeries(options) {
1299
1319
  const {
1300
1320
  filterOwner,
@@ -1347,6 +1367,13 @@ class WidgetRemoteSource extends WidgetSource {
1347
1367
  });
1348
1368
  }
1349
1369
  }
1370
+ WidgetBaseSource.defaultProps = {
1371
+ apiVersion: ApiVersion.V3,
1372
+ apiBaseUrl: DEFAULT_API_BASE_URL,
1373
+ clientId: getClient(),
1374
+ filters: {},
1375
+ filtersLogicalOperator: 'and'
1376
+ };
1350
1377
 
1351
1378
  /**
1352
1379
  * Source for Widget API requests on a data source defined by a SQL query.
@@ -1370,7 +1397,7 @@ class WidgetRemoteSource extends WidgetSource {
1370
1397
  * const { widgetSource } = await data;
1371
1398
  * ```
1372
1399
  */
1373
- class WidgetQuerySource extends WidgetRemoteSource {
1400
+ class WidgetQuerySource extends WidgetBaseSource {
1374
1401
  getModelSource(owner) {
1375
1402
  return _extends({}, super._getModelSource(owner), {
1376
1403
  type: 'query',
@@ -1402,7 +1429,7 @@ class WidgetQuerySource extends WidgetRemoteSource {
1402
1429
  * const { widgetSource } = await data;
1403
1430
  * ```
1404
1431
  */
1405
- class WidgetTableSource extends WidgetRemoteSource {
1432
+ class WidgetTableSource extends WidgetBaseSource {
1406
1433
  getModelSource(owner) {
1407
1434
  return _extends({}, super._getModelSource(owner), {
1408
1435
  type: 'table',
@@ -1411,1883 +1438,41 @@ class WidgetTableSource extends WidgetRemoteSource {
1411
1438
  }
1412
1439
  }
1413
1440
 
1414
- function makeIntervalComplete(intervals) {
1415
- return intervals.map(val => {
1416
- if (val[0] === undefined || val[0] === null) {
1417
- return [Number.MIN_SAFE_INTEGER, val[1]];
1418
- }
1419
- if (val[1] === undefined || val[1] === null) {
1420
- return [val[0], Number.MAX_SAFE_INTEGER];
1421
- }
1422
- return val;
1423
- });
1424
- }
1425
-
1426
- const filterFunctions = {
1427
- [FilterType.IN]: filterIn,
1428
- [FilterType.BETWEEN]: filterBetween,
1429
- [FilterType.TIME]: filterTime,
1430
- [FilterType.CLOSED_OPEN]: filterClosedOpen,
1431
- [FilterType.STRING_SEARCH]: filterStringSearch
1432
- };
1433
- function filterIn(filterValues, featureValue) {
1434
- return filterValues.includes(featureValue);
1435
- }
1436
- // FilterTypes.BETWEEN
1437
- function filterBetween(filterValues, featureValue) {
1438
- const checkRange = range => {
1439
- const [lowerBound, upperBound] = range;
1440
- return featureValue >= lowerBound && featureValue <= upperBound;
1441
+ const h3QuerySource = async function h3QuerySource(options) {
1442
+ const {
1443
+ aggregationExp,
1444
+ aggregationResLevel = DEFAULT_AGGREGATION_RES_LEVEL_H3,
1445
+ sqlQuery,
1446
+ spatialDataColumn = 'h3',
1447
+ queryParameters,
1448
+ filters
1449
+ } = options;
1450
+ const spatialDataType = 'h3';
1451
+ const urlParameters = {
1452
+ aggregationExp,
1453
+ spatialDataColumn,
1454
+ spatialDataType,
1455
+ q: sqlQuery
1441
1456
  };
1442
- return makeIntervalComplete(filterValues).some(checkRange);
1443
- }
1444
- function filterTime(filterValues, featureValue) {
1445
- const featureValueAsTimestamp = new Date(featureValue).getTime();
1446
- if (isFinite(featureValueAsTimestamp)) {
1447
- return filterBetween(filterValues, featureValueAsTimestamp);
1448
- } else {
1449
- throw new Error(`Column used to filter by time isn't well formatted.`);
1457
+ if (aggregationResLevel) {
1458
+ urlParameters.aggregationResLevel = String(aggregationResLevel);
1450
1459
  }
1451
- }
1452
- // FilterTypes.CLOSED_OPEN
1453
- function filterClosedOpen(filterValues, featureValue) {
1454
- const checkRange = range => {
1455
- const [lowerBound, upperBound] = range;
1456
- return featureValue >= lowerBound && featureValue < upperBound;
1457
- };
1458
- return makeIntervalComplete(filterValues).some(checkRange);
1459
- }
1460
- // FilterTypes.STRING_SEARCH
1461
- function filterStringSearch(filterValues, featureValue, params = {}) {
1462
- const normalizedFeatureValue = normalize(featureValue, params);
1463
- const stringRegExp = params.useRegExp ? filterValues : filterValues.map(filterValue => {
1464
- let stringRegExp = escapeRegExp(normalize(filterValue, params));
1465
- if (params.mustStart) stringRegExp = `^${stringRegExp}`;
1466
- if (params.mustEnd) stringRegExp = `${stringRegExp}$`;
1467
- return stringRegExp;
1468
- });
1469
- const regex = new RegExp(stringRegExp.join('|'), params.caseSensitive ? 'g' : 'gi');
1470
- return !!normalizedFeatureValue.match(regex);
1471
- }
1472
- // Aux
1473
- const specialCharRegExp = /[.*+?^${}()|[\]\\]/g;
1474
- const normalizeRegExp = /(?:[\^`\xA8\xAF\xB4\xB7\xB8\u02B0-\u034E\u0350-\u0357\u035D-\u0362\u0374\u0375\u037A\u0384\u0385\u0483-\u0487\u0559\u0591-\u05A1\u05A3-\u05BD\u05BF\u05C1\u05C2\u05C4\u064B-\u0652\u0657\u0658\u06DF\u06E0\u06E5\u06E6\u06EA-\u06EC\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F5\u0818\u0819\u0898-\u089F\u08C9-\u08D2\u08E3-\u08FE\u093C\u094D\u0951-\u0954\u0971\u09BC\u09CD\u0A3C\u0A4D\u0ABC\u0ACD\u0AFD-\u0AFF\u0B3C\u0B4D\u0B55\u0BCD\u0C3C\u0C4D\u0CBC\u0CCD\u0D3B\u0D3C\u0D4D\u0DCA\u0E3A\u0E47-\u0E4C\u0E4E\u0EBA\u0EC8-\u0ECC\u0F18\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F82-\u0F84\u0F86\u0F87\u0FC6\u1037\u1039\u103A\u1063\u1064\u1069-\u106D\u1087-\u108D\u108F\u109A\u109B\u135D-\u135F\u1714\u1715\u1734\u17C9-\u17D3\u17DD\u1939-\u193B\u1A60\u1A75-\u1A7C\u1A7F\u1AB0-\u1ABE\u1AC1-\u1ACB\u1B34\u1B44\u1B6B-\u1B73\u1BAA\u1BAB\u1BE6\u1BF2\u1BF3\u1C36\u1C37\u1C78-\u1C7D\u1CD0-\u1CE8\u1CED\u1CF4\u1CF7-\u1CF9\u1D2C-\u1D6A\u1DC4-\u1DCF\u1DF5-\u1DFF\u1FBD\u1FBF-\u1FC1\u1FCD-\u1FCF\u1FDD-\u1FDF\u1FED-\u1FEF\u1FFD\u1FFE\u2CEF-\u2CF1\u2E2F\u302A-\u302F\u3099-\u309C\u30FC\uA66F\uA67C\uA67D\uA67F\uA69C\uA69D\uA6F0\uA6F1\uA700-\uA721\uA788-\uA78A\uA7F8\uA7F9\uA806\uA82C\uA8C4\uA8E0-\uA8F1\uA92B-\uA92E\uA953\uA9B3\uA9C0\uA9E5\uAA7B-\uAA7D\uAABF-\uAAC2\uAAF6\uAB5B-\uAB5F\uAB69-\uAB6B\uABEC\uABED\uFB1E\uFE20-\uFE2F\uFF3E\uFF40\uFF70\uFF9E\uFF9F\uFFE3]|\uD800\uDEE0|\uD801[\uDF80-\uDF85\uDF87-\uDFB0\uDFB2-\uDFBA]|\uD802[\uDE38-\uDE3A\uDE3F\uDEE5\uDEE6]|\uD803[\uDD22-\uDD27\uDD4E\uDD69-\uDD6D\uDEFD-\uDEFF\uDF46-\uDF50\uDF82-\uDF85]|\uD804[\uDC46\uDC70\uDCB9\uDCBA\uDD33\uDD34\uDD73\uDDC0\uDDCA-\uDDCC\uDE35\uDE36\uDEE9\uDEEA\uDF3B\uDF3C\uDF4D\uDF66-\uDF6C\uDF70-\uDF74\uDFCE-\uDFD0\uDFD2\uDFD3\uDFE1\uDFE2]|\uD805[\uDC42\uDC46\uDCC2\uDCC3\uDDBF\uDDC0\uDE3F\uDEB6\uDEB7\uDF2B]|\uD806[\uDC39\uDC3A\uDD3D\uDD3E\uDD43\uDDE0\uDE34\uDE47\uDE99]|\uD807[\uDC3F\uDD42\uDD44\uDD45\uDD97\uDF41\uDF42\uDF5A]|\uD80D[\uDC47-\uDC55]|\uD818\uDD2F|\uD81A[\uDEF0-\uDEF4\uDF30-\uDF36]|\uD81B[\uDD6B\uDD6C\uDF8F-\uDF9F\uDFF0\uDFF1]|\uD82B[\uDFF0-\uDFF3\uDFF5-\uDFFB\uDFFD\uDFFE]|\uD833[\uDF00-\uDF2D\uDF30-\uDF46]|\uD834[\uDD67-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD]|\uD838[\uDC30-\uDC6D\uDD30-\uDD36\uDEAE\uDEEC-\uDEEF]|\uD839[\uDDEE\uDDEF]|\uD83A[\uDCD0-\uDCD6\uDD44-\uDD46\uDD48-\uDD4A])/g;
1475
- function escapeRegExp(value) {
1476
- return value.replace(specialCharRegExp, '\\$&');
1477
- }
1478
- function normalize(data, params) {
1479
- let normalizedData = String(data);
1480
- if (!params.keepSpecialCharacters) normalizedData = normalizedData.normalize('NFD').replace(normalizeRegExp, '');
1481
- return normalizedData;
1482
- }
1483
-
1484
- const LOGICAL_OPERATOR_METHODS = {
1485
- and: 'every',
1486
- or: 'some'
1487
- };
1488
- function passesFilter(columns, filters, feature, filtersLogicalOperator) {
1489
- const method = LOGICAL_OPERATOR_METHODS[filtersLogicalOperator];
1490
- return columns[method](column => {
1491
- const columnFilters = filters[column];
1492
- const columnFilterTypes = Object.keys(columnFilters);
1493
- if (!feature || feature[column] === null || feature[column] === undefined) {
1494
- return false;
1495
- }
1496
- return columnFilterTypes.every(filter => {
1497
- const filterFunction = filterFunctions[filter];
1498
- if (!filterFunction) {
1499
- throw new Error(`"${filter}" filter is not implemented.`);
1500
- }
1501
- return filterFunction(columnFilters[filter].values, feature[column], columnFilters[filter].params);
1502
- });
1503
- });
1504
- }
1505
- function buildFeatureFilter({
1506
- filters = {},
1507
- type = 'boolean',
1508
- filtersLogicalOperator = 'and'
1509
- }) {
1510
- const columns = Object.keys(filters);
1511
- if (!columns.length) {
1512
- return () => type === 'number' ? 1 : true;
1513
- }
1514
- return feature => {
1515
- const f = feature.properties || feature;
1516
- const featurePassesFilter = passesFilter(columns, filters, f, filtersLogicalOperator);
1517
- return type === 'number' ? Number(featurePassesFilter) : featurePassesFilter;
1518
- };
1519
- }
1520
- // Apply certain filters to a collection of features
1521
- function applyFilters(features, filters, filtersLogicalOperator) {
1522
- return Object.keys(filters).length ? features.filter(buildFeatureFilter({
1523
- filters,
1524
- filtersLogicalOperator
1525
- })) : features;
1526
- }
1527
- // Binary
1528
- function buildBinaryFeatureFilter({
1529
- filters = {}
1530
- }) {
1531
- const columns = Object.keys(filters);
1532
- if (!columns.length) {
1533
- return () => 1;
1460
+ if (queryParameters) {
1461
+ urlParameters.queryParameters = queryParameters;
1534
1462
  }
1535
- return (featureIdIdx, binaryData) => passesFilterUsingBinary(columns, filters, featureIdIdx, binaryData);
1536
- }
1537
- function getValueFromNumericProps(featureIdIdx, binaryData, {
1538
- column
1539
- }) {
1540
- var _binaryData$numericPr;
1541
- return (_binaryData$numericPr = binaryData.numericProps) == null || (_binaryData$numericPr = _binaryData$numericPr[column]) == null ? void 0 : _binaryData$numericPr.value[featureIdIdx];
1542
- }
1543
- function getValueFromProperties(featureIdIdx, binaryData, {
1544
- column
1545
- }) {
1546
- var _binaryData$propertie;
1547
- const propertyIdx = binaryData.featureIds.value[featureIdIdx];
1548
- return (_binaryData$propertie = binaryData.properties[propertyIdx]) == null ? void 0 : _binaryData$propertie[column];
1549
- }
1550
- const GET_VALUE_BY_BINARY_PROP = {
1551
- properties: getValueFromProperties,
1552
- numericProps: getValueFromNumericProps
1463
+ if (filters) {
1464
+ urlParameters.filters = filters;
1465
+ }
1466
+ return baseSource('query', options, urlParameters).then(result => _extends({}, result, {
1467
+ widgetSource: new WidgetQuerySource(_extends({}, options, {
1468
+ // NOTE: Parameters with default values above must be explicitly passed here.
1469
+ spatialDataColumn,
1470
+ spatialDataType
1471
+ }))
1472
+ }));
1553
1473
  };
1554
- function getBinaryPropertyByFilterValues(filterValues) {
1555
- return typeof filterValues.flat()[0] === 'string' ? 'properties' : 'numericProps';
1556
- }
1557
- function getFeatureValue(featureIdIdx, binaryData, filter) {
1558
- const {
1559
- column,
1560
- values
1561
- } = filter;
1562
- const binaryProp = getBinaryPropertyByFilterValues(values);
1563
- const getFeatureValueFn = GET_VALUE_BY_BINARY_PROP[binaryProp];
1564
- return getFeatureValueFn(featureIdIdx, binaryData, {
1565
- column
1566
- });
1567
- }
1568
- function passesFilterUsingBinary(columns, filters, featureIdIdx, binaryData) {
1569
- return columns.every(column => {
1570
- const columnFilters = filters[column];
1571
- return Object.entries(columnFilters).every(([type, {
1572
- values
1573
- }]) => {
1574
- const filterFn = filterFunctions[type];
1575
- if (!filterFn) {
1576
- throw new Error(`"${type}" filter is not implemented.`);
1577
- }
1578
- if (!values) return 0;
1579
- const featureValue = getFeatureValue(featureIdIdx, binaryData, {
1580
- type: type,
1581
- column,
1582
- values
1583
- });
1584
- if (featureValue === undefined || featureValue === null) return 0;
1585
- return filterFn(values, featureValue);
1586
- });
1587
- });
1588
- }
1589
-
1590
- function geojsonFeatures({
1591
- geojson,
1592
- spatialFilter,
1593
- uniqueIdProperty
1594
- }) {
1595
- let uniqueIdx = 0;
1596
- const map = new Map();
1597
- if (!spatialFilter) {
1598
- return [];
1599
- }
1600
- for (const feature of geojson.features) {
1601
- const uniqueId = uniqueIdProperty ? feature.properties[uniqueIdProperty] : ++uniqueIdx;
1602
- if (!map.has(uniqueId) && intersects(spatialFilter, feature)) {
1603
- map.set(uniqueId, feature.properties);
1604
- }
1605
- }
1606
- return Array.from(map.values());
1607
- }
1608
-
1609
- // math.gl
1610
- // SPDX-License-Identifier: MIT
1611
- // Copyright (c) vis.gl contributors
1612
- const DEFAULT_CONFIG = {
1613
- EPSILON: 1e-12,
1614
- debug: false,
1615
- precision: 4,
1616
- printTypes: false,
1617
- printDegrees: false,
1618
- printRowMajor: true,
1619
- _cartographicRadians: false
1620
- };
1621
- // Configuration is truly global as of v3.6 to ensure single config even if multiple copies of math.gl
1622
- // Multiple copies of config can be quite tricky to debug...
1623
- globalThis.mathgl = globalThis.mathgl || {
1624
- config: {
1625
- ...DEFAULT_CONFIG
1626
- }
1627
- };
1628
- /**
1629
- * Check if value is an "array"
1630
- * Returns `true` if value is either an array or a typed array
1631
- * Note: returns `false` for `ArrayBuffer` and `DataView` instances
1632
- * @note isTypedArray and isNumericArray are often more useful in TypeScript
1633
- */
1634
- function isArray(value) {
1635
- return Array.isArray(value) || ArrayBuffer.isView(value) && !(value instanceof DataView);
1636
- }
1637
- function lerp(a, b, t) {
1638
- if (isArray(a)) {
1639
- return a.map((ai, i) => lerp(ai, b[i], t));
1640
- }
1641
- return t * b + (1 - t) * a;
1642
- }
1643
-
1644
- // Replacement for the external assert method to reduce bundle size
1645
- // Note: We don't use the second "message" argument in calling code,
1646
- // so no need to support it here
1647
- function assert(condition, message) {
1648
- if (!condition) {
1649
- throw new Error(message || '@math.gl/web-mercator: assertion failed.');
1650
- }
1651
- }
1652
-
1653
- // TODO - THE UTILITIES IN THIS FILE SHOULD BE IMPORTED FROM WEB-MERCATOR-VIEWPORT MODULE
1654
- // CONSTANTS
1655
- const PI = Math.PI;
1656
- const PI_4 = PI / 4;
1657
- const DEGREES_TO_RADIANS = PI / 180;
1658
- const RADIANS_TO_DEGREES = 180 / PI;
1659
- const TILE_SIZE = 512;
1660
- /**
1661
- * Project [lng,lat] on sphere onto [x,y] on 512*512 Mercator Zoom 0 tile.
1662
- * Performs the nonlinear part of the web mercator projection.
1663
- * Remaining projection is done with 4x4 matrices which also handles
1664
- * perspective.
1665
- *
1666
- * @param lngLat - [lng, lat] coordinates
1667
- * Specifies a point on the sphere to project onto the map.
1668
- * @return [x,y] coordinates.
1669
- */
1670
- function lngLatToWorld(lngLat) {
1671
- const [lng, lat] = lngLat;
1672
- assert(Number.isFinite(lng));
1673
- assert(Number.isFinite(lat) && lat >= -90 && lat <= 90, 'invalid latitude');
1674
- const lambda2 = lng * DEGREES_TO_RADIANS;
1675
- const phi2 = lat * DEGREES_TO_RADIANS;
1676
- const x = TILE_SIZE * (lambda2 + PI) / (2 * PI);
1677
- const y = TILE_SIZE * (PI + Math.log(Math.tan(PI_4 + phi2 * 0.5))) / (2 * PI);
1678
- return [x, y];
1679
- }
1680
- /**
1681
- * Unproject world point [x,y] on map onto {lat, lon} on sphere
1682
- *
1683
- * @param xy - array with [x,y] members
1684
- * representing point on projected map plane
1685
- * @return - array with [x,y] of point on sphere.
1686
- * Has toArray method if you need a GeoJSON Array.
1687
- * Per cartographic tradition, lat and lon are specified as degrees.
1688
- */
1689
- function worldToLngLat(xy) {
1690
- const [x, y] = xy;
1691
- const lambda2 = x / TILE_SIZE * (2 * PI) - PI;
1692
- const phi2 = 2 * (Math.atan(Math.exp(y / TILE_SIZE * (2 * PI) - PI)) - PI_4);
1693
- return [lambda2 * RADIANS_TO_DEGREES, phi2 * RADIANS_TO_DEGREES];
1694
- }
1695
-
1696
- const TRANSFORM_FN$1 = {
1697
- Point: transformPoint$1,
1698
- MultiPoint: transformMultiPoint$1,
1699
- LineString: transformLineString$1,
1700
- MultiLineString: transformMultiLineString$1,
1701
- Polygon: transformPolygon$1,
1702
- MultiPolygon: transformMultiPolygon$1
1703
- };
1704
- /**
1705
- * Transform WGS84 coordinates to tile coords.
1706
- * It's the inverse of deck.gl coordinate-transform (https://github.com/visgl/deck.gl/blob/master/modules/geo-layers/src/mvt-layer/coordinate-transform.js)
1707
- *
1708
- * @param geometry - any valid geojson geometry
1709
- * @param bbox - geojson bbox
1710
- */
1711
- function transformToTileCoords(geometry, bbox) {
1712
- const [west, south, east, north] = bbox;
1713
- const nw = projectFlat([west, north]);
1714
- const se = projectFlat([east, south]);
1715
- const projectedBbox = [nw, se];
1716
- if (geometry.type === 'GeometryCollection') {
1717
- throw new Error('Unsupported geometry type GeometryCollection');
1718
- }
1719
- const transformFn = TRANSFORM_FN$1[geometry.type];
1720
- const coordinates = transformFn(geometry.coordinates, projectedBbox);
1721
- return _extends({}, geometry, {
1722
- coordinates
1723
- });
1724
- }
1725
- function transformPoint$1([pointX, pointY], [nw, se]) {
1726
- const x = inverseLerp(nw[0], se[0], pointX);
1727
- const y = inverseLerp(nw[1], se[1], pointY);
1728
- return [x, y];
1729
- }
1730
- function getPoints$1(geometry, bbox) {
1731
- return geometry.map(g => transformPoint$1(projectFlat(g), bbox));
1732
- }
1733
- function transformMultiPoint$1(multiPoint, bbox) {
1734
- return getPoints$1(multiPoint, bbox);
1735
- }
1736
- function transformLineString$1(line, bbox) {
1737
- return getPoints$1(line, bbox);
1738
- }
1739
- function transformMultiLineString$1(multiLineString, bbox) {
1740
- return multiLineString.map(lineString => transformLineString$1(lineString, bbox));
1741
- }
1742
- function transformPolygon$1(polygon, bbox) {
1743
- return polygon.map(polygonRing => getPoints$1(polygonRing, bbox));
1744
- }
1745
- function transformMultiPolygon$1(multiPolygon, bbox) {
1746
- return multiPolygon.map(polygon => transformPolygon$1(polygon, bbox));
1747
- }
1748
- function projectFlat(xyz) {
1749
- return lngLatToWorld(xyz);
1750
- }
1751
- function inverseLerp(a, b, x) {
1752
- return (x - a) / (b - a);
1753
- }
1754
-
1755
- const TRANSFORM_FN = {
1756
- Point: transformPoint,
1757
- MultiPoint: transformMultiPoint,
1758
- LineString: transformLineString,
1759
- MultiLineString: transformMultiLineString,
1760
- Polygon: transformPolygon,
1761
- MultiPolygon: transformMultiPolygon
1762
- };
1763
- /**
1764
- * Transform tile coords to WGS84 coordinates.
1765
- *
1766
- * @param geometry - any valid geojson geometry
1767
- * @param bbox - geojson bbox
1768
- */
1769
- function transformTileCoordsToWGS84(geometry, bbox) {
1770
- const [west, south, east, north] = bbox;
1771
- const nw = lngLatToWorld([west, north]);
1772
- const se = lngLatToWorld([east, south]);
1773
- const projectedBbox = [nw, se];
1774
- if (geometry.type === 'GeometryCollection') {
1775
- throw new Error('Unsupported geometry type GeometryCollection');
1776
- }
1777
- const transformFn = TRANSFORM_FN[geometry.type];
1778
- const coordinates = transformFn(geometry.coordinates, projectedBbox);
1779
- return _extends({}, geometry, {
1780
- coordinates
1781
- });
1782
- }
1783
- function transformPoint([pointX, pointY], [nw, se]) {
1784
- const x = lerp(nw[0], se[0], pointX);
1785
- const y = lerp(nw[1], se[1], pointY);
1786
- return worldToLngLat([x, y]);
1787
- }
1788
- function getPoints(geometry, bbox) {
1789
- return geometry.map(g => transformPoint(g, bbox));
1790
- }
1791
- function transformMultiPoint(multiPoint, bbox) {
1792
- return getPoints(multiPoint, bbox);
1793
- }
1794
- function transformLineString(line, bbox) {
1795
- return getPoints(line, bbox);
1796
- }
1797
- function transformMultiLineString(multiLineString, bbox) {
1798
- return multiLineString.map(lineString => transformLineString(lineString, bbox));
1799
- }
1800
- function transformPolygon(polygon, bbox) {
1801
- return polygon.map(polygonRing => getPoints(polygonRing, bbox));
1802
- }
1803
- function transformMultiPolygon(multiPolygon, bbox) {
1804
- return multiPolygon.map(polygon => transformPolygon(polygon, bbox));
1805
- }
1806
-
1807
- const FEATURE_GEOM_PROPERTY = '__geomValue';
1808
- function tileFeaturesGeometries({
1809
- tiles,
1810
- tileFormat,
1811
- spatialFilter,
1812
- uniqueIdProperty,
1813
- options
1814
- }) {
1815
- const map = new Map();
1816
- for (const tile of tiles) {
1817
- // Discard if it's not a visible tile (only check false value, not undefined)
1818
- // or tile has not data
1819
- if (tile.isVisible === false || !tile.data) {
1820
- continue;
1821
- }
1822
- const bbox = [tile.bbox.west, tile.bbox.south, tile.bbox.east, tile.bbox.north];
1823
- const bboxToGeom = bboxPolygon(bbox);
1824
- const tileIsFullyVisible = booleanWithin(bboxToGeom, spatialFilter);
1825
- // Clip the geometry to intersect with the tile
1826
- const spatialFilterFeature = {
1827
- type: 'Feature',
1828
- geometry: spatialFilter,
1829
- properties: {}
1830
- };
1831
- const clippedGeometryToIntersect = intersect(featureCollection([bboxToGeom, spatialFilterFeature]));
1832
- if (!clippedGeometryToIntersect) {
1833
- continue;
1834
- }
1835
- // We assume that MVT tileFormat uses local coordinates so we transform the geometry to intersect to tile coordinates [0..1],
1836
- // while in the case of 'geojson' or binary, the geometries are already in WGS84
1837
- const transformedGeometryToIntersect = tileFormat === TileFormat.MVT ? transformToTileCoords(clippedGeometryToIntersect.geometry, bbox) : clippedGeometryToIntersect.geometry;
1838
- createIndicesForPoints(tile.data.points);
1839
- calculateFeatures({
1840
- map,
1841
- tileIsFullyVisible,
1842
- geometryIntersection: transformedGeometryToIntersect,
1843
- data: tile.data.points,
1844
- type: 'Point',
1845
- bbox,
1846
- tileFormat,
1847
- uniqueIdProperty,
1848
- options
1849
- });
1850
- calculateFeatures({
1851
- map,
1852
- tileIsFullyVisible,
1853
- geometryIntersection: transformedGeometryToIntersect,
1854
- data: tile.data.lines,
1855
- type: 'LineString',
1856
- bbox,
1857
- tileFormat,
1858
- uniqueIdProperty,
1859
- options
1860
- });
1861
- calculateFeatures({
1862
- map,
1863
- tileIsFullyVisible,
1864
- geometryIntersection: transformedGeometryToIntersect,
1865
- data: tile.data.polygons,
1866
- type: 'Polygon',
1867
- bbox,
1868
- tileFormat,
1869
- uniqueIdProperty,
1870
- options
1871
- });
1872
- }
1873
- return Array.from(map.values());
1874
- }
1875
- function processTileFeatureProperties({
1876
- map,
1877
- data,
1878
- startIndex,
1879
- endIndex,
1880
- type,
1881
- bbox,
1882
- tileFormat,
1883
- uniqueIdProperty,
1884
- storeGeometry,
1885
- geometryIntersection
1886
- }) {
1887
- const tileProps = getPropertiesFromTile(data, startIndex);
1888
- const uniquePropertyValue = getUniquePropertyValue(tileProps, uniqueIdProperty, map);
1889
- if (!uniquePropertyValue || map.has(uniquePropertyValue)) {
1890
- return;
1891
- }
1892
- let geometry = null;
1893
- // Only calculate geometry if necessary
1894
- if (storeGeometry || geometryIntersection) {
1895
- const {
1896
- positions
1897
- } = data;
1898
- const ringCoordinates = getRingCoordinatesFor(startIndex, endIndex, positions);
1899
- geometry = getFeatureByType(ringCoordinates, type);
1900
- }
1901
- // If intersection is required, check before proceeding
1902
- if (geometry && geometryIntersection && !intersects(geometry, geometryIntersection)) {
1903
- return;
1904
- }
1905
- const properties = parseProperties(tileProps);
1906
- // Only save geometry if necessary
1907
- if (storeGeometry && geometry) {
1908
- properties[FEATURE_GEOM_PROPERTY] = tileFormat === TileFormat.MVT ? transformTileCoordsToWGS84(geometry, bbox) : geometry;
1909
- }
1910
- map.set(uniquePropertyValue, properties);
1911
- }
1912
- function addIntersectedFeaturesInTile({
1913
- map,
1914
- data,
1915
- geometryIntersection,
1916
- type,
1917
- bbox,
1918
- tileFormat,
1919
- uniqueIdProperty,
1920
- options
1921
- }) {
1922
- const indices = getIndices(data);
1923
- const storeGeometry = (options == null ? void 0 : options.storeGeometry) || false;
1924
- for (let i = 0; i < indices.length - 1; i++) {
1925
- const startIndex = indices[i];
1926
- const endIndex = indices[i + 1];
1927
- processTileFeatureProperties({
1928
- map,
1929
- data,
1930
- startIndex,
1931
- endIndex,
1932
- type,
1933
- bbox,
1934
- tileFormat,
1935
- uniqueIdProperty,
1936
- storeGeometry,
1937
- geometryIntersection
1938
- });
1939
- }
1940
- }
1941
- function getIndices(data) {
1942
- let indices;
1943
- switch (data.type) {
1944
- case 'Point':
1945
- // @ts-expect-error Missing or changed types?
1946
- indices = data.pointIndices;
1947
- break;
1948
- case 'LineString':
1949
- indices = data.pathIndices;
1950
- break;
1951
- case 'Polygon':
1952
- indices = data.primitivePolygonIndices;
1953
- break;
1954
- default:
1955
- throw new Error(`Unexpected type, "${data.type}"`);
1956
- }
1957
- return indices.value;
1958
- }
1959
- function getFeatureId(data, startIndex) {
1960
- return data.featureIds.value[startIndex];
1961
- }
1962
- function getPropertiesFromTile(data, startIndex) {
1963
- var _fields$featureId;
1964
- const featureId = getFeatureId(data, startIndex);
1965
- const {
1966
- properties,
1967
- numericProps,
1968
- fields
1969
- } = data;
1970
- const result = {
1971
- uniqueId: fields == null || (_fields$featureId = fields[featureId]) == null ? void 0 : _fields$featureId.id,
1972
- properties: properties[featureId],
1973
- numericProps: {}
1974
- };
1975
- for (const key in numericProps) {
1976
- result.numericProps[key] = numericProps[key].value[startIndex];
1977
- }
1978
- return result;
1979
- }
1980
- function parseProperties(tileProps) {
1981
- const {
1982
- properties,
1983
- numericProps
1984
- } = tileProps;
1985
- return Object.assign({}, properties, numericProps);
1986
- }
1987
- function getUniquePropertyValue(tileProps, uniqueIdProperty, map) {
1988
- if (uniqueIdProperty) {
1989
- return getValueFromTileProps(tileProps, uniqueIdProperty);
1990
- }
1991
- if (tileProps.uniqueId) {
1992
- return tileProps.uniqueId;
1993
- }
1994
- const artificialId = map.size + 1; // a counter, assumed as a valid new id
1995
- return getValueFromTileProps(tileProps, 'cartodb_id') || getValueFromTileProps(tileProps, 'geoid') || artificialId;
1996
- }
1997
- function getValueFromTileProps(tileProps, propertyName) {
1998
- const {
1999
- properties,
2000
- numericProps
2001
- } = tileProps;
2002
- return numericProps[propertyName] || properties[propertyName];
2003
- }
2004
- function getFeatureByType(coordinates, type) {
2005
- switch (type) {
2006
- case 'Polygon':
2007
- return {
2008
- type: 'Polygon',
2009
- coordinates: [coordinates]
2010
- };
2011
- case 'LineString':
2012
- return {
2013
- type: 'LineString',
2014
- coordinates
2015
- };
2016
- case 'Point':
2017
- return {
2018
- type: 'Point',
2019
- coordinates: coordinates[0]
2020
- };
2021
- default:
2022
- throw new Error('Invalid geometry type');
2023
- }
2024
- }
2025
- function getRingCoordinatesFor(startIndex, endIndex, positions) {
2026
- const ringCoordinates = [];
2027
- for (let j = startIndex; j < endIndex; j++) {
2028
- ringCoordinates.push(Array.from(positions.value.subarray(j * positions.size, (j + 1) * positions.size)));
2029
- }
2030
- return ringCoordinates;
2031
- }
2032
- function calculateFeatures({
2033
- map,
2034
- tileIsFullyVisible,
2035
- geometryIntersection,
2036
- data,
2037
- type,
2038
- bbox,
2039
- tileFormat,
2040
- uniqueIdProperty,
2041
- options
2042
- }) {
2043
- if (!(data != null && data.properties.length)) {
2044
- return;
2045
- }
2046
- if (tileIsFullyVisible) {
2047
- addAllFeaturesInTile({
2048
- map,
2049
- data,
2050
- type,
2051
- bbox,
2052
- tileFormat,
2053
- uniqueIdProperty,
2054
- options
2055
- });
2056
- } else {
2057
- addIntersectedFeaturesInTile({
2058
- map,
2059
- data,
2060
- geometryIntersection,
2061
- type,
2062
- bbox,
2063
- tileFormat,
2064
- uniqueIdProperty,
2065
- options
2066
- });
2067
- }
2068
- }
2069
- function addAllFeaturesInTile({
2070
- map,
2071
- data,
2072
- type,
2073
- bbox,
2074
- tileFormat,
2075
- uniqueIdProperty,
2076
- options
2077
- }) {
2078
- const indices = getIndices(data);
2079
- const storeGeometry = (options == null ? void 0 : options.storeGeometry) || false;
2080
- for (let i = 0; i < indices.length - 1; i++) {
2081
- const startIndex = indices[i];
2082
- const endIndex = indices[i + 1];
2083
- processTileFeatureProperties({
2084
- map,
2085
- data,
2086
- startIndex,
2087
- endIndex,
2088
- type,
2089
- bbox,
2090
- tileFormat,
2091
- uniqueIdProperty,
2092
- storeGeometry
2093
- });
2094
- }
2095
- }
2096
- function createIndicesForPoints(data) {
2097
- const featureIds = data.featureIds.value;
2098
- const lastFeatureId = featureIds[featureIds.length - 1];
2099
- const PointIndicesArray = featureIds.constructor;
2100
- const pointIndices = {
2101
- value: new PointIndicesArray(featureIds.length + 1),
2102
- size: 1
2103
- };
2104
- pointIndices.value.set(featureIds);
2105
- pointIndices.value.set([lastFeatureId + 1], featureIds.length);
2106
- // @ts-expect-error Missing or changed types?
2107
- data.pointIndices = pointIndices;
2108
- }
2109
-
2110
- // a tile is an array [x,y,z]
2111
- var d2r = Math.PI / 180,
2112
- r2d = 180 / Math.PI;
2113
- function tileToBBOX(tile) {
2114
- var e = tile2lon(tile[0] + 1, tile[2]);
2115
- var w = tile2lon(tile[0], tile[2]);
2116
- var s = tile2lat(tile[1] + 1, tile[2]);
2117
- var n = tile2lat(tile[1], tile[2]);
2118
- return [w, s, e, n];
2119
- }
2120
- function tileToGeoJSON(tile) {
2121
- var bbox = tileToBBOX(tile);
2122
- var poly = {
2123
- type: 'Polygon',
2124
- coordinates: [[[bbox[0], bbox[1]], [bbox[0], bbox[3]], [bbox[2], bbox[3]], [bbox[2], bbox[1]], [bbox[0], bbox[1]]]]
2125
- };
2126
- return poly;
2127
- }
2128
- function tile2lon(x, z) {
2129
- return x / Math.pow(2, z) * 360 - 180;
2130
- }
2131
- function tile2lat(y, z) {
2132
- var n = Math.PI - 2 * Math.PI * y / Math.pow(2, z);
2133
- return r2d * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)));
2134
- }
2135
- function pointToTile(lon, lat, z) {
2136
- var tile = pointToTileFraction(lon, lat, z);
2137
- tile[0] = Math.floor(tile[0]);
2138
- tile[1] = Math.floor(tile[1]);
2139
- return tile;
2140
- }
2141
- function getChildren(tile) {
2142
- return [[tile[0] * 2, tile[1] * 2, tile[2] + 1], [tile[0] * 2 + 1, tile[1] * 2, tile[2] + 1], [tile[0] * 2 + 1, tile[1] * 2 + 1, tile[2] + 1], [tile[0] * 2, tile[1] * 2 + 1, tile[2] + 1]];
2143
- }
2144
- function getParent(tile) {
2145
- // top left
2146
- if (tile[0] % 2 === 0 && tile[1] % 2 === 0) {
2147
- return [tile[0] / 2, tile[1] / 2, tile[2] - 1];
2148
- }
2149
- // bottom left
2150
- else if (tile[0] % 2 === 0 && !tile[1] % 2 === 0) {
2151
- return [tile[0] / 2, (tile[1] - 1) / 2, tile[2] - 1];
2152
- }
2153
- // top right
2154
- else if (!tile[0] % 2 === 0 && tile[1] % 2 === 0) {
2155
- return [(tile[0] - 1) / 2, tile[1] / 2, tile[2] - 1];
2156
- }
2157
- // bottom right
2158
- else {
2159
- return [(tile[0] - 1) / 2, (tile[1] - 1) / 2, tile[2] - 1];
2160
- }
2161
- }
2162
- function getSiblings(tile) {
2163
- return getChildren(getParent(tile));
2164
- }
2165
- function hasSiblings(tile, tiles) {
2166
- var siblings = getSiblings(tile);
2167
- for (var i = 0; i < siblings.length; i++) {
2168
- if (!hasTile(tiles, siblings[i])) return false;
2169
- }
2170
- return true;
2171
- }
2172
- function hasTile(tiles, tile) {
2173
- for (var i = 0; i < tiles.length; i++) {
2174
- if (tilesEqual(tiles[i], tile)) return true;
2175
- }
2176
- return false;
2177
- }
2178
- function tilesEqual(tile1, tile2) {
2179
- return tile1[0] === tile2[0] && tile1[1] === tile2[1] && tile1[2] === tile2[2];
2180
- }
2181
- function tileToQuadkey(tile) {
2182
- var index = '';
2183
- for (var z = tile[2]; z > 0; z--) {
2184
- var b = 0;
2185
- var mask = 1 << z - 1;
2186
- if ((tile[0] & mask) !== 0) b++;
2187
- if ((tile[1] & mask) !== 0) b += 2;
2188
- index += b.toString();
2189
- }
2190
- return index;
2191
- }
2192
- function quadkeyToTile(quadkey) {
2193
- var x = 0;
2194
- var y = 0;
2195
- var z = quadkey.length;
2196
- for (var i = z; i > 0; i--) {
2197
- var mask = 1 << i - 1;
2198
- switch (quadkey[z - i]) {
2199
- case '0':
2200
- break;
2201
- case '1':
2202
- x |= mask;
2203
- break;
2204
- case '2':
2205
- y |= mask;
2206
- break;
2207
- case '3':
2208
- x |= mask;
2209
- y |= mask;
2210
- break;
2211
- }
2212
- }
2213
- return [x, y, z];
2214
- }
2215
- function bboxToTile(bboxCoords) {
2216
- var min = pointToTile(bboxCoords[0], bboxCoords[1], 32);
2217
- var max = pointToTile(bboxCoords[2], bboxCoords[3], 32);
2218
- var bbox = [min[0], min[1], max[0], max[1]];
2219
- var z = getBboxZoom(bbox);
2220
- if (z === 0) return [0, 0, 0];
2221
- var x = bbox[0] >>> 32 - z;
2222
- var y = bbox[1] >>> 32 - z;
2223
- return [x, y, z];
2224
- }
2225
- function getBboxZoom(bbox) {
2226
- var MAX_ZOOM = 28;
2227
- for (var z = 0; z < MAX_ZOOM; z++) {
2228
- var mask = 1 << 32 - (z + 1);
2229
- if ((bbox[0] & mask) != (bbox[2] & mask) || (bbox[1] & mask) != (bbox[3] & mask)) {
2230
- return z;
2231
- }
2232
- }
2233
- return MAX_ZOOM;
2234
- }
2235
- function pointToTileFraction(lon, lat, z) {
2236
- var sin = Math.sin(lat * d2r),
2237
- z2 = Math.pow(2, z),
2238
- x = z2 * (lon / 360 + 0.5),
2239
- y = z2 * (0.5 - 0.25 * Math.log((1 + sin) / (1 - sin)) / Math.PI);
2240
- return [x, y, z];
2241
- }
2242
- var tilebelt = {
2243
- tileToGeoJSON: tileToGeoJSON,
2244
- tileToBBOX: tileToBBOX,
2245
- getChildren: getChildren,
2246
- getParent: getParent,
2247
- getSiblings: getSiblings,
2248
- hasTile: hasTile,
2249
- hasSiblings: hasSiblings,
2250
- tilesEqual: tilesEqual,
2251
- tileToQuadkey: tileToQuadkey,
2252
- quadkeyToTile: quadkeyToTile,
2253
- pointToTile: pointToTile,
2254
- bboxToTile: bboxToTile,
2255
- pointToTileFraction: pointToTileFraction
2256
- };
2257
-
2258
- /**
2259
- * Given a geometry, create cells and return them in their raw form,
2260
- * as an array of cell identifiers.
2261
- *
2262
- * @alias tiles
2263
- * @param {Object} geom GeoJSON geometry
2264
- * @param {Object} limits an object with min_zoom and max_zoom properties
2265
- * specifying the minimum and maximum level to be tiled.
2266
- * @returns {Array<Array<number>>} An array of tiles given as [x, y, z] arrays
2267
- */
2268
- var tiles = getTiles;
2269
- function getTiles(geom, limits) {
2270
- var i,
2271
- tile,
2272
- coords = geom.coordinates,
2273
- maxZoom = limits.max_zoom,
2274
- tileHash = {},
2275
- tiles = [];
2276
- if (geom.type === 'Point') {
2277
- return [tilebelt.pointToTile(coords[0], coords[1], maxZoom)];
2278
- } else if (geom.type === 'MultiPoint') {
2279
- for (i = 0; i < coords.length; i++) {
2280
- tile = tilebelt.pointToTile(coords[i][0], coords[i][1], maxZoom);
2281
- tileHash[toID(tile[0], tile[1], tile[2])] = true;
2282
- }
2283
- } else if (geom.type === 'LineString') {
2284
- lineCover(tileHash, coords, maxZoom);
2285
- } else if (geom.type === 'MultiLineString') {
2286
- for (i = 0; i < coords.length; i++) {
2287
- lineCover(tileHash, coords[i], maxZoom);
2288
- }
2289
- } else if (geom.type === 'Polygon') {
2290
- polygonCover(tileHash, tiles, coords, maxZoom);
2291
- } else if (geom.type === 'MultiPolygon') {
2292
- for (i = 0; i < coords.length; i++) {
2293
- polygonCover(tileHash, tiles, coords[i], maxZoom);
2294
- }
2295
- } else {
2296
- throw new Error('Geometry type not implemented');
2297
- }
2298
- if (limits.min_zoom !== maxZoom) {
2299
- // sync tile hash and tile array so that both contain the same tiles
2300
- var len = tiles.length;
2301
- appendHashTiles(tileHash, tiles);
2302
- for (i = 0; i < len; i++) {
2303
- var t = tiles[i];
2304
- tileHash[toID(t[0], t[1], t[2])] = true;
2305
- }
2306
- return mergeTiles(tileHash, tiles, limits);
2307
- }
2308
- appendHashTiles(tileHash, tiles);
2309
- return tiles;
2310
- }
2311
- function mergeTiles(tileHash, tiles, limits) {
2312
- var mergedTiles = [];
2313
- for (var z = limits.max_zoom; z > limits.min_zoom; z--) {
2314
- var parentTileHash = {};
2315
- var parentTiles = [];
2316
- for (var i = 0; i < tiles.length; i++) {
2317
- var t = tiles[i];
2318
- if (t[0] % 2 === 0 && t[1] % 2 === 0) {
2319
- var id2 = toID(t[0] + 1, t[1], z),
2320
- id3 = toID(t[0], t[1] + 1, z),
2321
- id4 = toID(t[0] + 1, t[1] + 1, z);
2322
- if (tileHash[id2] && tileHash[id3] && tileHash[id4]) {
2323
- tileHash[toID(t[0], t[1], t[2])] = false;
2324
- tileHash[id2] = false;
2325
- tileHash[id3] = false;
2326
- tileHash[id4] = false;
2327
- var parentTile = [t[0] / 2, t[1] / 2, z - 1];
2328
- if (z - 1 === limits.min_zoom) mergedTiles.push(parentTile);else {
2329
- parentTileHash[toID(t[0] / 2, t[1] / 2, z - 1)] = true;
2330
- parentTiles.push(parentTile);
2331
- }
2332
- }
2333
- }
2334
- }
2335
- for (i = 0; i < tiles.length; i++) {
2336
- t = tiles[i];
2337
- if (tileHash[toID(t[0], t[1], t[2])]) mergedTiles.push(t);
2338
- }
2339
- tileHash = parentTileHash;
2340
- tiles = parentTiles;
2341
- }
2342
- return mergedTiles;
2343
- }
2344
- function polygonCover(tileHash, tileArray, geom, zoom) {
2345
- var intersections = [];
2346
- for (var i = 0; i < geom.length; i++) {
2347
- var ring = [];
2348
- lineCover(tileHash, geom[i], zoom, ring);
2349
- for (var j = 0, len = ring.length, k = len - 1; j < len; k = j++) {
2350
- var m = (j + 1) % len;
2351
- var y = ring[j][1];
2352
-
2353
- // add interesction if it's not local extremum or duplicate
2354
- if ((y > ring[k][1] || y > ring[m][1]) && (
2355
- // not local minimum
2356
- y < ring[k][1] || y < ring[m][1]) &&
2357
- // not local maximum
2358
- y !== ring[m][1]) intersections.push(ring[j]);
2359
- }
2360
- }
2361
- intersections.sort(compareTiles); // sort by y, then x
2362
-
2363
- for (i = 0; i < intersections.length; i += 2) {
2364
- // fill tiles between pairs of intersections
2365
- y = intersections[i][1];
2366
- for (var x = intersections[i][0] + 1; x < intersections[i + 1][0]; x++) {
2367
- var id = toID(x, y, zoom);
2368
- if (!tileHash[id]) {
2369
- tileArray.push([x, y, zoom]);
2370
- }
2371
- }
2372
- }
2373
- }
2374
- function compareTiles(a, b) {
2375
- return a[1] - b[1] || a[0] - b[0];
2376
- }
2377
- function lineCover(tileHash, coords, maxZoom, ring) {
2378
- var prevX, prevY;
2379
- for (var i = 0; i < coords.length - 1; i++) {
2380
- var start = tilebelt.pointToTileFraction(coords[i][0], coords[i][1], maxZoom),
2381
- stop = tilebelt.pointToTileFraction(coords[i + 1][0], coords[i + 1][1], maxZoom),
2382
- x0 = start[0],
2383
- y0 = start[1],
2384
- x1 = stop[0],
2385
- y1 = stop[1],
2386
- dx = x1 - x0,
2387
- dy = y1 - y0;
2388
- if (dy === 0 && dx === 0) continue;
2389
- var sx = dx > 0 ? 1 : -1,
2390
- sy = dy > 0 ? 1 : -1,
2391
- x = Math.floor(x0),
2392
- y = Math.floor(y0),
2393
- tMaxX = dx === 0 ? Infinity : Math.abs(((dx > 0 ? 1 : 0) + x - x0) / dx),
2394
- tMaxY = dy === 0 ? Infinity : Math.abs(((dy > 0 ? 1 : 0) + y - y0) / dy),
2395
- tdx = Math.abs(sx / dx),
2396
- tdy = Math.abs(sy / dy);
2397
- if (x !== prevX || y !== prevY) {
2398
- tileHash[toID(x, y, maxZoom)] = true;
2399
- if (ring && y !== prevY) ring.push([x, y]);
2400
- prevX = x;
2401
- prevY = y;
2402
- }
2403
- while (tMaxX < 1 || tMaxY < 1) {
2404
- if (tMaxX < tMaxY) {
2405
- tMaxX += tdx;
2406
- x += sx;
2407
- } else {
2408
- tMaxY += tdy;
2409
- y += sy;
2410
- }
2411
- tileHash[toID(x, y, maxZoom)] = true;
2412
- if (ring && y !== prevY) ring.push([x, y]);
2413
- prevX = x;
2414
- prevY = y;
2415
- }
2416
- }
2417
- if (ring && y === ring[0][1]) ring.pop();
2418
- }
2419
- function appendHashTiles(hash, tiles) {
2420
- var keys = Object.keys(hash);
2421
- for (var i = 0; i < keys.length; i++) {
2422
- tiles.push(fromID(+keys[i]));
2423
- }
2424
- }
2425
- function toID(x, y, z) {
2426
- var dim = 2 * (1 << z);
2427
- return (dim * y + x) * 32 + z;
2428
- }
2429
- function fromID(id) {
2430
- var z = id % 32,
2431
- dim = 2 * (1 << z),
2432
- xy = (id - z) / 32,
2433
- x = xy % dim,
2434
- y = (xy - x) / dim % dim;
2435
- return [x, y, z];
2436
- }
2437
-
2438
- const B = [0x5555555555555555n, 0x3333333333333333n, 0x0f0f0f0f0f0f0f0fn, 0x00ff00ff00ff00ffn, 0x0000ffff0000ffffn, 0x00000000ffffffffn];
2439
- const S = [0n, 1n, 2n, 4n, 8n, 16n];
2440
- function tileToCell(tile) {
2441
- if (tile.z < 0 || tile.z > 26) {
2442
- throw new Error('Wrong zoom');
2443
- }
2444
- const z = BigInt(tile.z);
2445
- let x = BigInt(tile.x) << 32n - z;
2446
- let y = BigInt(tile.y) << 32n - z;
2447
- for (let i = 0; i < 5; i++) {
2448
- const s = S[5 - i];
2449
- const b = B[4 - i];
2450
- x = (x | x << s) & b;
2451
- y = (y | y << s) & b;
2452
- }
2453
- const quadbin = 0x4000000000000000n | 1n << 59n |
2454
- // | (mode << 59) | (mode_dep << 57)
2455
- z << 52n | (x | y << 1n) >> 12n | 0xfffffffffffffn >> z * 2n;
2456
- return quadbin;
2457
- }
2458
- function getResolution$1(quadbin) {
2459
- return quadbin >> 52n & 0x1fn;
2460
- }
2461
- function geometryToCells(geometry, resolution) {
2462
- const zoom = Number(resolution);
2463
- return tiles(geometry, {
2464
- min_zoom: zoom,
2465
- max_zoom: zoom
2466
- }).map(([x, y, z]) => tileToCell({
2467
- x,
2468
- y,
2469
- z
2470
- }));
2471
- }
2472
-
2473
- function tileFeaturesSpatialIndex({
2474
- tiles,
2475
- spatialFilter,
2476
- spatialDataColumn,
2477
- spatialDataType
2478
- }) {
2479
- const map = new Map();
2480
- const spatialIndex = getSpatialIndex(spatialDataType);
2481
- const resolution = getResolution(tiles, spatialIndex);
2482
- const spatialIndexIDName = spatialDataColumn ? spatialDataColumn : spatialIndex;
2483
- if (!resolution) {
2484
- return [];
2485
- }
2486
- const cells = getCellsCoverGeometry(spatialFilter, spatialIndex, resolution);
2487
- if (!(cells != null && cells.length)) {
2488
- return [];
2489
- }
2490
- // We transform cells to Set to improve the performace
2491
- const cellsSet = new Set(cells);
2492
- for (const tile of tiles) {
2493
- if (tile.isVisible === false || !tile.data) {
2494
- continue;
2495
- }
2496
- tile.data.forEach(d => {
2497
- if (cellsSet.has(d.id)) {
2498
- map.set(d.id, _extends({}, d.properties, {
2499
- [spatialIndexIDName]: d.id
2500
- }));
2501
- }
2502
- });
2503
- }
2504
- return Array.from(map.values());
2505
- }
2506
- function getResolution(tiles, spatialIndex) {
2507
- var _tiles$find;
2508
- const data = (_tiles$find = tiles.find(tile => {
2509
- var _tile$data;
2510
- return (_tile$data = tile.data) == null ? void 0 : _tile$data.length;
2511
- })) == null ? void 0 : _tiles$find.data;
2512
- if (!data) {
2513
- return;
2514
- }
2515
- if (spatialIndex === SpatialIndex.QUADBIN) {
2516
- return Number(getResolution$1(data[0].id));
2517
- }
2518
- if (spatialIndex === SpatialIndex.H3) {
2519
- return getResolution$2(data[0].id);
2520
- }
2521
- }
2522
- const bboxWest = [-180, -90, 0, 90];
2523
- const bboxEast = [0, -90, 180, 90];
2524
- function getCellsCoverGeometry(geometry, spatialIndex, resolution) {
2525
- if (spatialIndex === SpatialIndex.QUADBIN) {
2526
- // @ts-expect-error TODO: Probably ought to be stricter about number vs. bigint types in this file.
2527
- return geometryToCells(geometry, resolution);
2528
- }
2529
- if (spatialIndex === SpatialIndex.H3) {
2530
- // The current H3 polyfill algorithm can't deal with polygon segments of greater than 180 degrees longitude
2531
- // so we clip the geometry to be sure that none of them is greater than 180 degrees
2532
- // https://github.com/uber/h3-js/issues/24#issuecomment-431893796
2533
- return polygonToCells(bboxClip(geometry, bboxWest).geometry.coordinates, resolution, true).concat(polygonToCells(bboxClip(geometry, bboxEast).geometry.coordinates, resolution, true));
2534
- }
2535
- }
2536
- function getSpatialIndex(spatialDataType) {
2537
- switch (spatialDataType) {
2538
- case 'h3':
2539
- return SpatialIndex.H3;
2540
- case 'quadbin':
2541
- return SpatialIndex.QUADBIN;
2542
- default:
2543
- throw new Error('Unexpected spatial data type');
2544
- }
2545
- }
2546
-
2547
- /** @internalRemarks Source: @carto/react-core */
2548
- function tileFeatures({
2549
- tiles,
2550
- spatialFilter,
2551
- uniqueIdProperty,
2552
- tileFormat,
2553
- spatialDataColumn = DEFAULT_GEO_COLUMN,
2554
- spatialDataType,
2555
- options = {}
2556
- }) {
2557
- // TODO(cleanup): Is an empty response the expected result when spatialFilter
2558
- // is omitted? Why not make the parameter required, or return the full input?
2559
- if (!spatialFilter) {
2560
- return [];
2561
- }
2562
- if (spatialDataType !== 'geo') {
2563
- return tileFeaturesSpatialIndex({
2564
- tiles: tiles,
2565
- spatialFilter,
2566
- spatialDataColumn,
2567
- spatialDataType
2568
- });
2569
- }
2570
- return tileFeaturesGeometries({
2571
- tiles,
2572
- tileFormat,
2573
- spatialFilter,
2574
- uniqueIdProperty,
2575
- options
2576
- });
2577
- }
2578
-
2579
- /** @internalRemarks Source: @carto/react-core */
2580
- const aggregationFunctions = {
2581
- count: values => values.length,
2582
- min: (...args) => applyAggregationFunction(min, ...args),
2583
- max: (...args) => applyAggregationFunction(max, ...args),
2584
- sum: (...args) => applyAggregationFunction(sum, ...args),
2585
- avg: (...args) => applyAggregationFunction(avg, ...args)
2586
- };
2587
- /** @internalRemarks Source: @carto/react-core */
2588
- function aggregate(feature, keys, operation) {
2589
- if (!(keys != null && keys.length)) {
2590
- throw new Error('Cannot aggregate a feature without having keys');
2591
- } else if (keys.length === 1) {
2592
- const value = feature[keys[0]];
2593
- return isPotentiallyValidNumber(value) ? Number(value) : value;
2594
- }
2595
- const aggregationFn = aggregationFunctions[operation];
2596
- if (!aggregationFn) {
2597
- throw new Error(`${operation} isn't a valid aggregation function`);
2598
- }
2599
- return aggregationFn(keys.map(column => {
2600
- const value = feature[column];
2601
- return isPotentiallyValidNumber(value) ? Number(value) : value;
2602
- }));
2603
- }
2604
- /*
2605
- * Forced casting to Number (just of non empty strings) allows to work-around
2606
- * some specific situations, where a big numeric field is transformed into a string when generating the tileset(eg.PG)
2607
- */
2608
- function isPotentiallyValidNumber(value) {
2609
- return typeof value === 'string' && value.trim().length > 0;
2610
- }
2611
- const applyAggregationFunction = (aggFn, values, keys, operation) => {
2612
- const normalizedKeys = normalizeKeys(keys);
2613
- const elements = ((normalizedKeys == null ? void 0 : normalizedKeys.length) || 0) <= 1 ? filterFalsyElements(values, normalizedKeys || []) : values;
2614
- return aggFn(elements, keys, operation);
2615
- };
2616
- function filterFalsyElements(values, keys) {
2617
- const filterFn = value => value !== null && value !== undefined;
2618
- if (!(keys != null && keys.length)) {
2619
- return values.filter(filterFn);
2620
- }
2621
- return values.filter(v => filterFn(v[keys[0]]));
2622
- }
2623
- // Aggregation functions
2624
- function avg(values, keys, joinOperation) {
2625
- return sum(values, keys, joinOperation) / (values.length || 1);
2626
- }
2627
- function sum(values, keys, joinOperation) {
2628
- const normalizedKeys = normalizeKeys(keys);
2629
- if (normalizedKeys) {
2630
- return values.reduce((a, b) => a + aggregate(b, normalizedKeys, joinOperation), 0);
2631
- }
2632
- return values.reduce((a, b) => a + b, 0);
2633
- }
2634
- function min(values, keys, joinOperation) {
2635
- const normalizedKeys = normalizeKeys(keys);
2636
- if (normalizedKeys) {
2637
- return values.reduce((a, b) => Math.min(a, aggregate(b, normalizedKeys, joinOperation)), Infinity);
2638
- }
2639
- return Math.min(...values);
2640
- }
2641
- function max(values, keys, joinOperation) {
2642
- const normalizedKeys = normalizeKeys(keys);
2643
- if (normalizedKeys) {
2644
- return values.reduce((a, b) => Math.max(a, aggregate(b, normalizedKeys, joinOperation)), -Infinity);
2645
- }
2646
- return Math.max(...values);
2647
- }
2648
- // Aux
2649
- // Keys can come as a string (one column) or a strings array (multiple column)
2650
- // Use always an array to make the code easier
2651
- function normalizeKeys(keys) {
2652
- return Array.isArray(keys) ? keys : typeof keys === 'string' ? [keys] : undefined;
2653
- }
2654
-
2655
- /***
2656
- Copyright 2013 Teun Duynstee
2657
-
2658
- Licensed under the Apache License, Version 2.0 (the "License");
2659
- you may not use this file except in compliance with the License.
2660
- You may obtain a copy of the License at
2661
-
2662
- http://www.apache.org/licenses/LICENSE-2.0
2663
-
2664
- Unless required by applicable law or agreed to in writing, software
2665
- distributed under the License is distributed on an "AS IS" BASIS,
2666
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2667
- See the License for the specific language governing permissions and
2668
- limitations under the License.
2669
- */
2670
- var thenBy_module = function () {
2671
- function identity(v) {
2672
- return v;
2673
- }
2674
- function ignoreCase(v) {
2675
- return typeof v === "string" ? v.toLowerCase() : v;
2676
- }
2677
- function makeCompareFunction(f, opt) {
2678
- opt = typeof opt === "object" ? opt : {
2679
- direction: opt
2680
- };
2681
- if (typeof f != "function") {
2682
- var prop = f;
2683
- // make unary function
2684
- f = function (v1) {
2685
- return !!v1[prop] ? v1[prop] : "";
2686
- };
2687
- }
2688
- if (f.length === 1) {
2689
- // f is a unary function mapping a single item to its sort score
2690
- var uf = f;
2691
- var preprocess = opt.ignoreCase ? ignoreCase : identity;
2692
- var cmp = opt.cmp || function (v1, v2) {
2693
- return v1 < v2 ? -1 : v1 > v2 ? 1 : 0;
2694
- };
2695
- f = function (v1, v2) {
2696
- return cmp(preprocess(uf(v1)), preprocess(uf(v2)));
2697
- };
2698
- }
2699
- const descTokens = {
2700
- "-1": '',
2701
- desc: ''
2702
- };
2703
- if (opt.direction in descTokens) return function (v1, v2) {
2704
- return -f(v1, v2);
2705
- };
2706
- return f;
2707
- }
2708
-
2709
- /* adds a secondary compare function to the target function (`this` context)
2710
- which is applied in case the first one returns 0 (equal)
2711
- returns a new compare function, which has a `thenBy` method as well */
2712
- function tb(func, opt) {
2713
- /* should get value false for the first call. This can be done by calling the
2714
- exported function, or the firstBy property on it (for es6 module compatibility)
2715
- */
2716
- var x = typeof this == "function" && !this.firstBy ? this : false;
2717
- var y = makeCompareFunction(func, opt);
2718
- var f = x ? function (a, b) {
2719
- return x(a, b) || y(a, b);
2720
- } : y;
2721
- f.thenBy = tb;
2722
- return f;
2723
- }
2724
- tb.firstBy = tb;
2725
- return tb;
2726
- }();
2727
-
2728
- /**
2729
- * Apply sort structure to a collection of features
2730
- * @param features
2731
- * @param [sortOptions]
2732
- * @param [sortOptions.sortBy] - One or more columns to sort by
2733
- * @param [sortOptions.sortByDirection] - Direction by the columns will be sorted
2734
- * @param [sortOptions.sortByColumnType] - Column type
2735
- * @internal
2736
- * @internalRemarks Source: @carto/react-core
2737
- */
2738
- function applySorting(features, {
2739
- sortBy,
2740
- sortByDirection = 'asc',
2741
- sortByColumnType = 'string'
2742
- } = {}) {
2743
- // If sortBy is undefined, pass all features
2744
- if (sortBy === undefined) {
2745
- return features;
2746
- }
2747
- // sortOptions exists, but are bad formatted
2748
- const isValidSortBy = Array.isArray(sortBy) && sortBy.length ||
2749
- // sortBy can be an array of columns
2750
- typeof sortBy === 'string'; // or just one column
2751
- if (!isValidSortBy) {
2752
- throw new Error('Sorting options are bad formatted');
2753
- }
2754
- const sortFn = createSortFn({
2755
- sortBy,
2756
- sortByDirection,
2757
- sortByColumnType: sortByColumnType || 'string'
2758
- });
2759
- return features.sort(sortFn);
2760
- }
2761
- // Aux
2762
- function createSortFn({
2763
- sortBy,
2764
- sortByDirection,
2765
- sortByColumnType
2766
- }) {
2767
- const [firstSortOption, ...othersSortOptions] = normalizeSortByOptions({
2768
- sortBy,
2769
- sortByDirection,
2770
- sortByColumnType
2771
- });
2772
- let sortFn = thenBy_module.firstBy(...firstSortOption);
2773
- for (let sortOptions of othersSortOptions) {
2774
- sortFn = sortFn.thenBy(...sortOptions);
2775
- }
2776
- return sortFn;
2777
- }
2778
- function normalizeSortByOptions({
2779
- sortBy,
2780
- sortByDirection,
2781
- sortByColumnType
2782
- }) {
2783
- const numberFormat = sortByColumnType === 'number' && {
2784
- cmp: (a, b) => a - b
2785
- };
2786
- if (!Array.isArray(sortBy)) {
2787
- sortBy = [sortBy];
2788
- }
2789
- return sortBy.map(sortByEl => {
2790
- // sortByEl is 'column'
2791
- if (typeof sortByEl === 'string') {
2792
- return [sortByEl, _extends({
2793
- direction: sortByDirection
2794
- }, numberFormat)];
2795
- }
2796
- if (Array.isArray(sortByEl)) {
2797
- // sortBy is ['column']
2798
- if (sortByEl[1] === undefined) {
2799
- return [sortByEl, _extends({
2800
- direction: sortByDirection
2801
- }, numberFormat)];
2802
- }
2803
- // sortBy is ['column', { ... }]
2804
- if (typeof sortByEl[1] === 'object') {
2805
- const othersSortOptions = numberFormat ? _extends({}, numberFormat, sortByEl[1]) : sortByEl[1];
2806
- return [sortByEl[0], _extends({
2807
- direction: sortByDirection
2808
- }, othersSortOptions)];
2809
- }
2810
- }
2811
- return sortByEl;
2812
- });
2813
- }
2814
-
2815
- /** @internalRemarks Source: @carto/react-core */
2816
- function groupValuesByColumn({
2817
- data,
2818
- valuesColumns,
2819
- joinOperation,
2820
- keysColumn,
2821
- operation
2822
- }) {
2823
- if (Array.isArray(data) && data.length === 0) {
2824
- return null;
2825
- }
2826
- const groups = data.reduce((accumulator, item) => {
2827
- const group = item[keysColumn];
2828
- const values = accumulator.get(group) || [];
2829
- accumulator.set(group, values);
2830
- const aggregatedValue = aggregate(item, valuesColumns, joinOperation);
2831
- const isValid = (operation === 'count' ? true : aggregatedValue !== null) && aggregatedValue !== undefined;
2832
- if (isValid) {
2833
- values.push(aggregatedValue);
2834
- accumulator.set(group, values);
2835
- }
2836
- return accumulator;
2837
- }, new Map()); // We use a map to be able to maintain the type in the key value
2838
- const targetOperation = aggregationFunctions[operation];
2839
- if (targetOperation) {
2840
- return Array.from(groups).map(([name, value]) => ({
2841
- name,
2842
- value: targetOperation(value)
2843
- }));
2844
- }
2845
- return [];
2846
- }
2847
-
2848
- /**
2849
- * Returns midnight (local time) on the Monday preceeding a given date, in
2850
- * milliseconds since the UNIX epoch.
2851
- */
2852
- /**
2853
- * Returns midnight (UTC) on the Monday preceeding a given date, in
2854
- * milliseconds since the UNIX epoch.
2855
- */
2856
- function getUTCMonday(date) {
2857
- const dateCp = new Date(date);
2858
- const day = dateCp.getUTCDay();
2859
- const diff = dateCp.getUTCDate() - day + (day ? 1 : -6); // adjust when day is sunday
2860
- dateCp.setUTCDate(diff);
2861
- return Date.UTC(dateCp.getUTCFullYear(), dateCp.getUTCMonth(), dateCp.getUTCDate());
2862
- }
2863
-
2864
- const GROUP_KEY_FN_MAPPING = {
2865
- year: date => Date.UTC(date.getUTCFullYear()),
2866
- month: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth()),
2867
- week: date => getUTCMonday(date),
2868
- day: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()),
2869
- hour: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours()),
2870
- minute: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes()),
2871
- second: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds())
2872
- };
2873
- /** @internalRemarks Source: @carto/react-core */
2874
- function groupValuesByDateColumn({
2875
- data,
2876
- valuesColumns,
2877
- joinOperation,
2878
- keysColumn,
2879
- groupType,
2880
- operation
2881
- }) {
2882
- if (Array.isArray(data) && data.length === 0) {
2883
- return null;
2884
- }
2885
- const groupKeyFn = GROUP_KEY_FN_MAPPING[groupType];
2886
- if (!groupKeyFn) {
2887
- return null;
2888
- }
2889
- const groups = data.reduce((acc, item) => {
2890
- const value = item[keysColumn];
2891
- const formattedValue = new Date(value);
2892
- const groupKey = groupKeyFn(formattedValue);
2893
- if (!isNaN(groupKey)) {
2894
- let groupedValues = acc.get(groupKey);
2895
- if (!groupedValues) {
2896
- groupedValues = [];
2897
- acc.set(groupKey, groupedValues);
2898
- }
2899
- const aggregatedValue = aggregate(item, valuesColumns, joinOperation);
2900
- const isValid = aggregatedValue !== null && aggregatedValue !== undefined;
2901
- if (isValid) {
2902
- groupedValues.push(aggregatedValue);
2903
- acc.set(groupKey, groupedValues);
2904
- }
2905
- }
2906
- return acc;
2907
- }, new Map());
2908
- const targetOperation = aggregationFunctions[operation];
2909
- return [...groups.entries()].map(([name, value]) => ({
2910
- name,
2911
- value: targetOperation(value)
2912
- })).sort((a, b) => a.name - b.name);
2913
- }
2914
-
2915
- /**
2916
- * Histogram computation.
2917
- * @internalRemarks Source: @carto/react-core
2918
- */
2919
- function histogram({
2920
- data,
2921
- valuesColumns,
2922
- joinOperation,
2923
- ticks,
2924
- operation
2925
- }) {
2926
- if (Array.isArray(data) && data.length === 0) {
2927
- return [];
2928
- }
2929
- const binsContainer = [Number.MIN_SAFE_INTEGER, ...ticks].map((tick, index, arr) => ({
2930
- bin: index,
2931
- start: tick,
2932
- end: index === arr.length - 1 ? Number.MAX_SAFE_INTEGER : arr[index + 1],
2933
- values: []
2934
- }));
2935
- data.forEach(feature => {
2936
- const featureValue = aggregate(feature, valuesColumns, joinOperation);
2937
- const isValid = featureValue !== null && featureValue !== undefined;
2938
- if (!isValid) {
2939
- return;
2940
- }
2941
- const binContainer = binsContainer.find(bin => bin.start <= featureValue && bin.end > featureValue);
2942
- if (!binContainer) {
2943
- return;
2944
- }
2945
- binContainer.values.push(featureValue);
2946
- });
2947
- const targetOperation = aggregationFunctions[operation];
2948
- const transformedBins = binsContainer.map(binContainer => binContainer.values);
2949
- return transformedBins.map(values => values.length ? targetOperation(values) : 0);
2950
- }
2951
-
2952
- /**
2953
- * Filters invalid features and formats data.
2954
- * @internalRemarks Source: @carto/react-core
2955
- */
2956
- function scatterPlot({
2957
- data,
2958
- xAxisColumns,
2959
- xAxisJoinOperation,
2960
- yAxisColumns,
2961
- yAxisJoinOperation
2962
- }) {
2963
- return data.reduce((acc, feature) => {
2964
- const xValue = aggregate(feature, xAxisColumns, xAxisJoinOperation);
2965
- const xIsValid = xValue !== null && xValue !== undefined;
2966
- const yValue = aggregate(feature, yAxisColumns, yAxisJoinOperation);
2967
- const yIsValid = yValue !== null && yValue !== undefined;
2968
- if (xIsValid && yIsValid) {
2969
- acc.push([xValue, yValue]);
2970
- }
2971
- return acc;
2972
- }, []);
2973
- }
2974
-
2975
- const _excluded = ["filterOwner", "spatialFilter", "abortController"];
2976
- /**
2977
- * Source for Widget API requests on a data source defined by a tileset.
2978
- *
2979
- * Generally not intended to be constructed directly. Instead, call
2980
- * {@link vectorTilesetSource}, {@link h3TilesetSource}, or {@link quadbinTilesetSource},
2981
- * which can be shared with map layers. Sources contain a `widgetSource`
2982
- * property, for use by widget implementations.
2983
- *
2984
- * Example:
2985
- *
2986
- * ```javascript
2987
- * import { vectorTilesetSource } from '@carto/api-client';
2988
- *
2989
- * const data = vectorTilesetSource({
2990
- * accessToken: '••••',
2991
- * connectionName: 'carto_dw',
2992
- * tableName: 'carto-demo-data.demo_rasters.my_tileset_source'
2993
- * });
2994
- *
2995
- * const { widgetSource } = await data;
2996
- * ```
2997
- */
2998
- class WidgetTilesetSource extends WidgetSource {
2999
- constructor(...args) {
3000
- super(...args);
3001
- this._tiles = [];
3002
- this._features = [];
3003
- }
3004
- getModelSource(owner) {
3005
- return _extends({}, super._getModelSource(owner), {
3006
- type: 'tileset',
3007
- data: this.props.tableName
3008
- });
3009
- }
3010
- /**
3011
- * Loads features as a list of tiles (typically provided by deck.gl).
3012
- * After tiles are loaded, {@link extractTileFeatures} must be called
3013
- * before computing statistics on the tiles.
3014
- */
3015
- loadTiles(tiles) {
3016
- this._tiles = tiles;
3017
- }
3018
- /**
3019
- * Extracts feature data from tiles previously loaded with {@link loadTiles}.
3020
- * Must be called before computing statistics on tiles.
3021
- */
3022
- extractTileFeatures({
3023
- spatialFilter,
3024
- uniqueIdProperty,
3025
- options
3026
- }) {
3027
- this._features = tileFeatures({
3028
- tiles: this._tiles,
3029
- options,
3030
- spatialFilter,
3031
- uniqueIdProperty,
3032
- tileFormat: this.props.tileFormat,
3033
- spatialDataColumn: this.props.spatialDataColumn,
3034
- spatialDataType: this.props.spatialDataType
3035
- });
3036
- }
3037
- /** Loads features as GeoJSON (used for testing). */
3038
- loadGeoJSON({
3039
- geojson,
3040
- spatialFilter,
3041
- uniqueIdProperty
3042
- }) {
3043
- this._features = geojsonFeatures({
3044
- geojson,
3045
- spatialFilter,
3046
- uniqueIdProperty
3047
- });
3048
- }
3049
- async getFeatures(options) {
3050
- throw new Error('getFeatures not supported for tilesets');
3051
- }
3052
- async getFormula({
3053
- column = '*',
3054
- operation = 'count',
3055
- joinOperation,
3056
- filterOwner
3057
- }) {
3058
- if (operation === 'custom') {
3059
- throw new Error('Custom aggregation not supported for tilesets');
3060
- }
3061
- if (!this._features.length) {
3062
- return {
3063
- value: null
3064
- };
3065
- }
3066
- // Column is required except when operation is 'count'.
3067
- if (column && column !== '*' || operation !== 'count') {
3068
- assertColumn(this._features, column);
3069
- }
3070
- const filteredFeatures = this._getFilteredFeatures(filterOwner);
3071
- if (filteredFeatures.length === 0 && operation !== 'count') {
3072
- return {
3073
- value: null
3074
- };
3075
- }
3076
- const targetOperation = aggregationFunctions[operation];
3077
- return {
3078
- value: targetOperation(filteredFeatures, column, joinOperation)
3079
- };
3080
- }
3081
- async getHistogram({
3082
- operation = 'count',
3083
- ticks,
3084
- column,
3085
- joinOperation,
3086
- filterOwner
3087
- }) {
3088
- if (!this._features.length) {
3089
- return [];
3090
- }
3091
- const filteredFeatures = this._getFilteredFeatures(filterOwner);
3092
- assertColumn(this._features, column);
3093
- return histogram({
3094
- data: filteredFeatures,
3095
- valuesColumns: normalizeColumns(column),
3096
- joinOperation,
3097
- ticks,
3098
- operation
3099
- });
3100
- }
3101
- async getCategories({
3102
- column,
3103
- operation = 'count',
3104
- operationColumn,
3105
- joinOperation,
3106
- filterOwner
3107
- }) {
3108
- if (!this._features.length) {
3109
- return [];
3110
- }
3111
- const filteredFeatures = this._getFilteredFeatures(filterOwner);
3112
- assertColumn(this._features, column, operationColumn);
3113
- const groups = groupValuesByColumn({
3114
- data: filteredFeatures,
3115
- valuesColumns: normalizeColumns(operationColumn || column),
3116
- joinOperation,
3117
- keysColumn: column,
3118
- operation
3119
- });
3120
- return groups || [];
3121
- }
3122
- async getScatter({
3123
- xAxisColumn,
3124
- yAxisColumn,
3125
- xAxisJoinOperation,
3126
- yAxisJoinOperation,
3127
- filterOwner
3128
- }) {
3129
- if (!this._features.length) {
3130
- return [];
3131
- }
3132
- const filteredFeatures = this._getFilteredFeatures(filterOwner);
3133
- assertColumn(this._features, xAxisColumn, yAxisColumn);
3134
- return scatterPlot({
3135
- data: filteredFeatures,
3136
- xAxisColumns: normalizeColumns(xAxisColumn),
3137
- xAxisJoinOperation,
3138
- yAxisColumns: normalizeColumns(yAxisColumn),
3139
- yAxisJoinOperation
3140
- });
3141
- }
3142
- async getTable(options) {
3143
- const {
3144
- filterOwner
3145
- } = options,
3146
- params = _objectWithoutPropertiesLoose(options, _excluded);
3147
- const {
3148
- columns,
3149
- searchFilterColumn,
3150
- searchFilterText,
3151
- sortBy,
3152
- sortDirection,
3153
- sortByColumnType,
3154
- offset = 0,
3155
- limit = 10
3156
- } = params;
3157
- if (!this._features.length) {
3158
- return {
3159
- rows: [],
3160
- totalCount: 0
3161
- };
3162
- }
3163
- // Filter.
3164
- let filteredFeatures = this._getFilteredFeatures(filterOwner);
3165
- // Search.
3166
- // TODO: Could we get the same behavior by applying filters in loadTiles()?
3167
- if (searchFilterColumn && searchFilterText) {
3168
- filteredFeatures = filteredFeatures.filter(row => row[searchFilterColumn] && String(row[searchFilterColumn]).toLowerCase().includes(String(searchFilterText).toLowerCase()));
3169
- }
3170
- // Sort.
3171
- let rows = applySorting(filteredFeatures, {
3172
- sortBy,
3173
- sortByDirection: sortDirection,
3174
- sortByColumnType
3175
- });
3176
- const totalCount = rows.length;
3177
- // Offset and limit.
3178
- rows = rows.slice(Math.min(offset, totalCount), Math.min(offset + limit, totalCount));
3179
- // Select columns.
3180
- rows = rows.map(srcRow => {
3181
- const dstRow = {};
3182
- for (const column of columns) {
3183
- dstRow[column] = srcRow[column];
3184
- }
3185
- return dstRow;
3186
- });
3187
- return {
3188
- rows,
3189
- totalCount
3190
- };
3191
- }
3192
- async getTimeSeries({
3193
- column,
3194
- stepSize,
3195
- operation,
3196
- operationColumn,
3197
- joinOperation,
3198
- filterOwner
3199
- }) {
3200
- if (!this._features.length) {
3201
- return {
3202
- rows: []
3203
- };
3204
- }
3205
- const filteredFeatures = this._getFilteredFeatures(filterOwner);
3206
- assertColumn(this._features, column, operationColumn);
3207
- const rows = groupValuesByDateColumn({
3208
- data: filteredFeatures,
3209
- valuesColumns: normalizeColumns(operationColumn || column),
3210
- keysColumn: column,
3211
- groupType: stepSize,
3212
- operation,
3213
- joinOperation
3214
- }) || [];
3215
- return {
3216
- rows
3217
- };
3218
- }
3219
- async getRange({
3220
- column,
3221
- filterOwner
3222
- }) {
3223
- if (!this._features.length) {
3224
- // TODO: Is this the only nullable response in the Widgets API? If so,
3225
- // can we do something more consistent?
3226
- return null;
3227
- }
3228
- assertColumn(this._features, column);
3229
- const filteredFeatures = this._getFilteredFeatures(filterOwner);
3230
- return {
3231
- min: aggregationFunctions.min(filteredFeatures, column),
3232
- max: aggregationFunctions.max(filteredFeatures, column)
3233
- };
3234
- }
3235
- /****************************************************************************
3236
- * INTERNAL
3237
- */
3238
- _getFilteredFeatures(filterOwner) {
3239
- return applyFilters(this._features, getApplicableFilters(filterOwner, this.props.filters), this.props.filtersLogicalOperator || 'and');
3240
- }
3241
- }
3242
- function assertColumn(features, ...columnArgs) {
3243
- // TODO(cleanup): Can drop support for multiple column shapes here?
3244
- // Due to the multiple column shape, we normalise it as an array with normalizeColumns
3245
- const columns = Array.from(new Set(columnArgs.map(normalizeColumns).flat()));
3246
- const featureKeys = Object.keys(features[0]);
3247
- const invalidColumns = columns.filter(column => !featureKeys.includes(column));
3248
- if (invalidColumns.length) {
3249
- throw new InvalidColumnError(`Missing column(s): ${invalidColumns.join(', ')}`);
3250
- }
3251
- }
3252
- function normalizeColumns(columns) {
3253
- return Array.isArray(columns) ? columns : typeof columns === 'string' ? [columns] : [];
3254
- }
3255
-
3256
- const h3QuerySource = async function h3QuerySource(options) {
3257
- const {
3258
- aggregationExp,
3259
- aggregationResLevel = DEFAULT_AGGREGATION_RES_LEVEL_H3,
3260
- sqlQuery,
3261
- spatialDataColumn = 'h3',
3262
- queryParameters,
3263
- filters
3264
- } = options;
3265
- const spatialDataType = 'h3';
3266
- const urlParameters = {
3267
- aggregationExp,
3268
- spatialDataColumn,
3269
- spatialDataType,
3270
- q: sqlQuery
3271
- };
3272
- if (aggregationResLevel) {
3273
- urlParameters.aggregationResLevel = String(aggregationResLevel);
3274
- }
3275
- if (queryParameters) {
3276
- urlParameters.queryParameters = queryParameters;
3277
- }
3278
- if (filters) {
3279
- urlParameters.filters = filters;
3280
- }
3281
- return baseSource('query', options, urlParameters).then(result => _extends({}, result, {
3282
- widgetSource: new WidgetQuerySource(_extends({}, options, {
3283
- // NOTE: Parameters with default values above must be explicitly passed here.
3284
- spatialDataColumn,
3285
- spatialDataType
3286
- }))
3287
- }));
3288
- };
3289
-
3290
- const h3TableSource = async function h3TableSource(options) {
1474
+
1475
+ const h3TableSource = async function h3TableSource(options) {
3291
1476
  const {
3292
1477
  aggregationExp,
3293
1478
  aggregationResLevel = DEFAULT_AGGREGATION_RES_LEVEL_H3,
@@ -3317,26 +1502,17 @@ const h3TableSource = async function h3TableSource(options) {
3317
1502
  }));
3318
1503
  };
3319
1504
 
3320
- function getTileFormat(tilejson) {
3321
- const tileParams = new URL(tilejson.tiles[0]).searchParams;
3322
- return tileParams.get('formatTiles') === 'mvt' ? TileFormat.MVT : TileFormat.BINARY;
3323
- }
3324
-
1505
+ // deck.gl
1506
+ // SPDX-License-Identifier: MIT
1507
+ // Copyright (c) vis.gl contributors
3325
1508
  const h3TilesetSource = async function h3TilesetSource(options) {
3326
1509
  const {
3327
- tableName,
3328
- spatialDataColumn = 'h3'
1510
+ tableName
3329
1511
  } = options;
3330
1512
  const urlParameters = {
3331
1513
  name: tableName
3332
1514
  };
3333
- return baseSource('tileset', options, urlParameters).then(result => _extends({}, result, {
3334
- widgetSource: new WidgetTilesetSource(_extends({}, options, {
3335
- tileFormat: getTileFormat(result),
3336
- spatialDataColumn,
3337
- spatialDataType: 'h3'
3338
- }))
3339
- }));
1515
+ return baseSource('tileset', options, urlParameters);
3340
1516
  };
3341
1517
 
3342
1518
  // deck.gl
@@ -3420,28 +1596,24 @@ const quadbinTableSource = async function quadbinTableSource(options) {
3420
1596
  }));
3421
1597
  };
3422
1598
 
1599
+ // deck.gl
1600
+ // SPDX-License-Identifier: MIT
1601
+ // Copyright (c) vis.gl contributors
3423
1602
  const quadbinTilesetSource = async function quadbinTilesetSource(options) {
3424
1603
  const {
3425
- tableName,
3426
- spatialDataColumn = 'quadbin'
1604
+ tableName
3427
1605
  } = options;
3428
1606
  const urlParameters = {
3429
1607
  name: tableName
3430
1608
  };
3431
- return baseSource('tileset', options, urlParameters).then(result => _extends({}, result, {
3432
- widgetSource: new WidgetTilesetSource(_extends({}, options, {
3433
- tileFormat: getTileFormat(result),
3434
- spatialDataColumn,
3435
- spatialDataType: 'quadbin'
3436
- }))
3437
- }));
1609
+ return baseSource('tileset', options, urlParameters);
3438
1610
  };
3439
1611
 
3440
1612
  const vectorQuerySource = async function vectorQuerySource(options) {
3441
1613
  const {
3442
1614
  columns,
3443
1615
  filters,
3444
- spatialDataColumn = DEFAULT_GEO_COLUMN,
1616
+ spatialDataColumn = 'geom',
3445
1617
  sqlQuery,
3446
1618
  tileResolution = DEFAULT_TILE_RESOLUTION,
3447
1619
  queryParameters,
@@ -3480,7 +1652,7 @@ const vectorTableSource = async function vectorTableSource(options) {
3480
1652
  const {
3481
1653
  columns,
3482
1654
  filters,
3483
- spatialDataColumn = DEFAULT_GEO_COLUMN,
1655
+ spatialDataColumn = 'geom',
3484
1656
  tableName,
3485
1657
  tileResolution = DEFAULT_TILE_RESOLUTION,
3486
1658
  aggregationExp
@@ -3511,21 +1683,17 @@ const vectorTableSource = async function vectorTableSource(options) {
3511
1683
  }));
3512
1684
  };
3513
1685
 
1686
+ // deck.gl
1687
+ // SPDX-License-Identifier: MIT
1688
+ // Copyright (c) vis.gl contributors
3514
1689
  const vectorTilesetSource = async function vectorTilesetSource(options) {
3515
1690
  const {
3516
- tableName,
3517
- spatialDataColumn = DEFAULT_GEO_COLUMN
1691
+ tableName
3518
1692
  } = options;
3519
1693
  const urlParameters = {
3520
1694
  name: tableName
3521
1695
  };
3522
- return baseSource('tileset', options, urlParameters).then(result => _extends({}, result, {
3523
- widgetSource: new WidgetTilesetSource(_extends({}, options, {
3524
- tileFormat: getTileFormat(result),
3525
- spatialDataColumn,
3526
- spatialDataType: 'geo'
3527
- }))
3528
- }));
1696
+ return baseSource('tileset', options, urlParameters);
3529
1697
  };
3530
1698
 
3531
1699
  const query = async function query(options) {
@@ -3570,5 +1738,5 @@ const query = async function query(options) {
3570
1738
  });
3571
1739
  };
3572
1740
 
3573
- export { ApiVersion, CartoAPIError, DEFAULT_API_BASE_URL, FEATURE_GEOM_PROPERTY, FilterType, Provider, SOURCE_DEFAULTS, SpatialIndex, TileFormat, WidgetQuerySource, WidgetRemoteSource, WidgetSource, WidgetTableSource, WidgetTilesetSource, addFilter, aggregate, aggregationFunctions, applyFilters, applySorting, boundaryQuerySource, boundaryTableSource, buildBinaryFeatureFilter, buildFeatureFilter, buildPublicMapUrl, buildStatsUrl, clearFilters, createPolygonSpatialFilter, createViewportSpatialFilter, filterFunctions, geojsonFeatures, getClient, getFilter, groupValuesByColumn, groupValuesByDateColumn, h3QuerySource, h3TableSource, h3TilesetSource, hasFilter, histogram, makeIntervalComplete, quadbinQuerySource, quadbinTableSource, quadbinTilesetSource, query, rasterSource, removeFilter, requestWithParameters, scatterPlot, setClient, tileFeatures, tileFeaturesGeometries, tileFeaturesSpatialIndex, transformToTileCoords, vectorQuerySource, vectorTableSource, vectorTilesetSource };
1741
+ export { ApiVersion, CartoAPIError, DEFAULT_API_BASE_URL, FilterType, SOURCE_DEFAULTS, WidgetBaseSource, WidgetQuerySource, WidgetTableSource, _getHexagonResolution, addFilter, boundaryQuerySource, boundaryTableSource, buildPublicMapUrl, buildStatsUrl, clearFilters, createPolygonSpatialFilter, createViewportSpatialFilter, getClient, getFilter, h3QuerySource, h3TableSource, h3TilesetSource, hasFilter, quadbinQuerySource, quadbinTableSource, quadbinTilesetSource, query, rasterSource, removeFilter, requestWithParameters, setClient, vectorQuerySource, vectorTableSource, vectorTilesetSource };
3574
1742
  //# sourceMappingURL=api-client.modern.js.map