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