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