@carto/api-client 0.5.0-alpha.3 → 0.5.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/build/api/carto-api-error.d.ts +1 -1
- package/build/api/query.d.ts +1 -1
- package/build/api/request-with-parameters.d.ts +2 -2
- package/build/api-client.cjs +2324 -2188
- package/build/api-client.cjs.map +1 -1
- package/build/api-client.modern.js +2196 -2055
- package/build/api-client.modern.js.map +1 -1
- package/build/client.d.ts +2 -2
- package/build/constants-internal.d.ts +5 -5
- package/build/constants.d.ts +6 -6
- package/build/deck/get-data-filter-extension-props.d.ts +18 -0
- package/build/deck/index.d.ts +1 -0
- package/build/filters/Filter.d.ts +15 -3
- package/build/filters/FilterTypes.d.ts +1 -1
- package/build/filters/geosjonFeatures.d.ts +2 -2
- package/build/filters/tileFeatures.d.ts +8 -8
- package/build/filters/tileFeaturesRaster.d.ts +3 -3
- package/build/filters.d.ts +2 -2
- package/build/geo.d.ts +1 -1
- package/build/index.d.ts +1 -0
- package/build/models/common.d.ts +4 -3
- package/build/models/model.d.ts +2 -2
- package/build/operations/aggregation.d.ts +5 -5
- package/build/operations/applySorting.d.ts +3 -3
- package/build/operations/groupBy.d.ts +4 -4
- package/build/operations/groupByDate.d.ts +1 -1
- package/build/operations/histogram.d.ts +3 -3
- package/build/operations/scatterPlot.d.ts +3 -3
- package/build/sources/base-source.d.ts +2 -2
- package/build/sources/boundary-query-source.d.ts +1 -1
- package/build/sources/boundary-table-source.d.ts +1 -1
- package/build/sources/h3-query-source.d.ts +2 -2
- package/build/sources/h3-table-source.d.ts +2 -2
- package/build/sources/h3-tileset-source.d.ts +2 -2
- package/build/sources/index.d.ts +26 -26
- package/build/sources/quadbin-query-source.d.ts +2 -2
- package/build/sources/quadbin-table-source.d.ts +2 -2
- package/build/sources/quadbin-tileset-source.d.ts +2 -2
- package/build/sources/raster-source.d.ts +2 -2
- package/build/sources/types.d.ts +3 -3
- package/build/sources/vector-query-source.d.ts +1 -1
- package/build/sources/vector-table-source.d.ts +1 -1
- package/build/sources/vector-tileset-source.d.ts +2 -2
- package/build/spatial-index.d.ts +3 -3
- package/build/types-internal.d.ts +5 -5
- package/build/types.d.ts +15 -15
- package/build/utils/makeIntervalComplete.d.ts +1 -1
- package/build/utils.d.ts +3 -3
- package/build/widget-sources/types.d.ts +4 -2
- package/build/widget-sources/widget-query-source.d.ts +2 -1
- package/build/widget-sources/widget-remote-source.d.ts +3 -0
- package/build/widget-sources/widget-source.d.ts +3 -3
- package/build/widget-sources/widget-table-source.d.ts +2 -1
- package/build/widget-sources/widget-tileset-source.d.ts +22 -24
- package/package.json +36 -30
- package/src/api/carto-api-error.ts +1 -1
- package/src/api/query.ts +5 -5
- package/src/api/request-with-parameters.ts +6 -6
- package/src/client.ts +3 -3
- package/src/constants-internal.ts +5 -5
- package/src/constants.ts +6 -6
- package/src/deck/get-data-filter-extension-props.ts +146 -0
- package/src/deck/index.ts +1 -0
- package/src/filters/Filter.ts +18 -8
- package/src/filters/FilterTypes.ts +2 -2
- package/src/filters/geosjonFeatures.ts +2 -2
- package/src/filters/tileFeatures.ts +13 -19
- package/src/filters/tileFeaturesRaster.ts +7 -7
- package/src/filters.ts +4 -4
- package/src/geo.ts +12 -14
- package/src/index.ts +1 -0
- package/src/models/common.ts +9 -7
- package/src/models/model.ts +3 -4
- package/src/operations/aggregation.ts +5 -5
- package/src/operations/applySorting.ts +4 -4
- package/src/operations/groupBy.ts +4 -4
- package/src/operations/groupByDate.ts +1 -1
- package/src/operations/histogram.ts +4 -4
- package/src/operations/scatterPlot.ts +4 -4
- package/src/sources/base-source.ts +8 -8
- package/src/sources/boundary-query-source.ts +2 -2
- package/src/sources/boundary-table-source.ts +2 -2
- package/src/sources/h3-query-source.ts +7 -5
- package/src/sources/h3-table-source.ts +7 -5
- package/src/sources/h3-tileset-source.ts +4 -4
- package/src/sources/index.ts +26 -26
- package/src/sources/quadbin-query-source.ts +7 -5
- package/src/sources/quadbin-table-source.ts +7 -5
- package/src/sources/quadbin-tileset-source.ts +4 -4
- package/src/sources/raster-source.ts +8 -4
- package/src/sources/types.ts +3 -3
- package/src/sources/vector-query-source.ts +2 -3
- package/src/sources/vector-table-source.ts +2 -3
- package/src/sources/vector-tileset-source.ts +5 -5
- package/src/spatial-index.ts +4 -4
- package/src/types-internal.ts +5 -5
- package/src/types.ts +15 -15
- package/src/utils/makeIntervalComplete.ts +1 -1
- package/src/utils.ts +3 -3
- package/src/widget-sources/types.ts +5 -3
- package/src/widget-sources/widget-query-source.ts +6 -2
- package/src/widget-sources/widget-remote-source.ts +31 -16
- package/src/widget-sources/widget-source.ts +13 -4
- package/src/widget-sources/widget-table-source.ts +6 -2
- package/src/widget-sources/widget-tileset-source.ts +132 -81
|
@@ -1,24 +1,25 @@
|
|
|
1
|
-
import bboxClip from '@turf/bbox-clip';
|
|
2
|
-
import bboxPolygon from '@turf/bbox-polygon';
|
|
3
|
-
import union from '@turf/union';
|
|
4
|
-
import { getType } from '@turf/invariant';
|
|
5
|
-
import { featureCollection, feature, polygon, multiPolygon } from '@turf/helpers';
|
|
6
1
|
import intersects from '@turf/boolean-intersects';
|
|
2
|
+
import bboxPolygon from '@turf/bbox-polygon';
|
|
7
3
|
import booleanWithin from '@turf/boolean-within';
|
|
8
4
|
import intersect from '@turf/intersect';
|
|
5
|
+
import { featureCollection, feature, polygon, multiPolygon } from '@turf/helpers';
|
|
9
6
|
import { getResolution as getResolution$1, geometryToCells, cellToChildren, cellToTile } from 'quadbin';
|
|
7
|
+
import bboxClip from '@turf/bbox-clip';
|
|
10
8
|
import { getResolution as getResolution$2, polygonToCells } from 'h3-js';
|
|
9
|
+
import union from '@turf/union';
|
|
10
|
+
import { getType } from '@turf/invariant';
|
|
11
|
+
import { booleanEqual } from '@turf/boolean-equal';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* @internal
|
|
14
|
-
* @
|
|
15
|
+
* @privateRemarks Source: @carto/react-core, @carto/constants, @deck.gl/carto
|
|
15
16
|
*/
|
|
16
17
|
let client = 'deck-gl-carto';
|
|
17
18
|
/**
|
|
18
19
|
* Returns current client ID, used to categorize API requests. For internal use only.
|
|
19
20
|
*
|
|
20
21
|
* @internal
|
|
21
|
-
* @
|
|
22
|
+
* @privateRemarks Source: @carto/react-core
|
|
22
23
|
*/
|
|
23
24
|
function getClient() {
|
|
24
25
|
return client;
|
|
@@ -27,7 +28,7 @@ function getClient() {
|
|
|
27
28
|
* Sets current client ID, used to categorize API requests. For internal use only.
|
|
28
29
|
*
|
|
29
30
|
* @internal
|
|
30
|
-
* @
|
|
31
|
+
* @privateRemarks Source: @carto/react-core
|
|
31
32
|
*/
|
|
32
33
|
function setClient(c) {
|
|
33
34
|
client = c;
|
|
@@ -45,7 +46,7 @@ function setClient(c) {
|
|
|
45
46
|
* };
|
|
46
47
|
* ```
|
|
47
48
|
*
|
|
48
|
-
* @
|
|
49
|
+
* @privateRemarks Source: @carto/react-api, @deck.gl/carto
|
|
49
50
|
*/
|
|
50
51
|
var FilterType;
|
|
51
52
|
(function (FilterType) {
|
|
@@ -57,16 +58,16 @@ var FilterType;
|
|
|
57
58
|
FilterType["TIME"] = "time";
|
|
58
59
|
FilterType["STRING_SEARCH"] = "stringSearch";
|
|
59
60
|
})(FilterType || (FilterType = {}));
|
|
60
|
-
/** @
|
|
61
|
+
/** @privateRemarks Source: @carto/constants */
|
|
61
62
|
var ApiVersion;
|
|
62
63
|
(function (ApiVersion) {
|
|
63
64
|
ApiVersion["V1"] = "v1";
|
|
64
65
|
ApiVersion["V2"] = "v2";
|
|
65
66
|
ApiVersion["V3"] = "v3";
|
|
66
67
|
})(ApiVersion || (ApiVersion = {}));
|
|
67
|
-
/** @
|
|
68
|
+
/** @privateRemarks Source: @carto/constants, @deck.gl/carto */
|
|
68
69
|
const DEFAULT_API_BASE_URL = 'https://gcp-us-east1.api.carto.com';
|
|
69
|
-
/** @
|
|
70
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
70
71
|
var TileFormat;
|
|
71
72
|
(function (TileFormat) {
|
|
72
73
|
TileFormat["MVT"] = "mvt";
|
|
@@ -74,14 +75,14 @@ var TileFormat;
|
|
|
74
75
|
TileFormat["GEOJSON"] = "geojson";
|
|
75
76
|
TileFormat["BINARY"] = "binary";
|
|
76
77
|
})(TileFormat || (TileFormat = {}));
|
|
77
|
-
/** @
|
|
78
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
78
79
|
var SpatialIndex;
|
|
79
80
|
(function (SpatialIndex) {
|
|
80
81
|
SpatialIndex["H3"] = "h3";
|
|
81
82
|
SpatialIndex["S2"] = "s2";
|
|
82
83
|
SpatialIndex["QUADBIN"] = "quadbin";
|
|
83
84
|
})(SpatialIndex || (SpatialIndex = {}));
|
|
84
|
-
/** @
|
|
85
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
85
86
|
var Provider;
|
|
86
87
|
(function (Provider) {
|
|
87
88
|
Provider["BIGQUERY"] = "bigquery";
|
|
@@ -92,2187 +93,2314 @@ var Provider;
|
|
|
92
93
|
Provider["DATABRICKS_REST"] = "databricksRest";
|
|
93
94
|
})(Provider || (Provider = {}));
|
|
94
95
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
*/
|
|
101
|
-
function getApplicableFilters(owner, filters) {
|
|
102
|
-
if (!filters) return {};
|
|
103
|
-
const applicableFilters = {};
|
|
104
|
-
for (const column in filters) {
|
|
105
|
-
for (const type in filters[column]) {
|
|
106
|
-
if (!isFilterType(type)) continue;
|
|
107
|
-
const filter = filters[column][type];
|
|
108
|
-
const isApplicable = !owner || !(filter != null && filter.owner) || (filter == null ? void 0 : filter.owner) !== owner;
|
|
109
|
-
if (filter && isApplicable) {
|
|
110
|
-
applicableFilters[column] || (applicableFilters[column] = {});
|
|
111
|
-
applicableFilters[column][type] = filter;
|
|
112
|
-
}
|
|
96
|
+
function _extends() {
|
|
97
|
+
return _extends = Object.assign ? Object.assign.bind() : function (n) {
|
|
98
|
+
for (var e = 1; e < arguments.length; e++) {
|
|
99
|
+
var t = arguments[e];
|
|
100
|
+
for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
|
|
113
101
|
}
|
|
114
|
-
|
|
115
|
-
|
|
102
|
+
return n;
|
|
103
|
+
}, _extends.apply(null, arguments);
|
|
116
104
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
*/
|
|
124
|
-
function normalizeObjectKeys(el) {
|
|
125
|
-
if (Array.isArray(el)) {
|
|
126
|
-
return el.map(value => normalizeObjectKeys(value));
|
|
127
|
-
} else if (typeof el !== 'object') {
|
|
128
|
-
return el;
|
|
105
|
+
function _objectWithoutPropertiesLoose(r, e) {
|
|
106
|
+
if (null == r) return {};
|
|
107
|
+
var t = {};
|
|
108
|
+
for (var n in r) if ({}.hasOwnProperty.call(r, n)) {
|
|
109
|
+
if (e.includes(n)) continue;
|
|
110
|
+
t[n] = r[n];
|
|
129
111
|
}
|
|
130
|
-
return
|
|
131
|
-
acc[key.toLowerCase()] = typeof value === 'object' && value ? normalizeObjectKeys(value) : value;
|
|
132
|
-
return acc;
|
|
133
|
-
}, {});
|
|
112
|
+
return t;
|
|
134
113
|
}
|
|
135
|
-
|
|
136
|
-
function
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
114
|
+
|
|
115
|
+
function makeIntervalComplete(intervals) {
|
|
116
|
+
return intervals.map(val => {
|
|
117
|
+
if (val[0] === undefined || val[0] === null) {
|
|
118
|
+
return [Number.MIN_SAFE_INTEGER, val[1]];
|
|
119
|
+
}
|
|
120
|
+
if (val[1] === undefined || val[1] === null) {
|
|
121
|
+
return [val[0], Number.MAX_SAFE_INTEGER];
|
|
122
|
+
}
|
|
123
|
+
return val;
|
|
124
|
+
});
|
|
140
125
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
var _error$message;
|
|
152
|
-
return error instanceof InvalidColumnError || ((_error$message = error.message) == null ? void 0 : _error$message.includes(InvalidColumnError.NAME));
|
|
153
|
-
}
|
|
126
|
+
|
|
127
|
+
const filterFunctions = {
|
|
128
|
+
[FilterType.IN]: filterIn,
|
|
129
|
+
[FilterType.BETWEEN]: filterBetween,
|
|
130
|
+
[FilterType.TIME]: filterTime,
|
|
131
|
+
[FilterType.CLOSED_OPEN]: filterClosedOpen,
|
|
132
|
+
[FilterType.STRING_SEARCH]: filterStringSearch
|
|
133
|
+
};
|
|
134
|
+
function filterIn(filterValues, featureValue) {
|
|
135
|
+
return filterValues.includes(featureValue);
|
|
154
136
|
}
|
|
155
|
-
|
|
156
|
-
function
|
|
157
|
-
|
|
158
|
-
|
|
137
|
+
// FilterTypes.BETWEEN
|
|
138
|
+
function filterBetween(filterValues, featureValue) {
|
|
139
|
+
const checkRange = range => {
|
|
140
|
+
const [lowerBound, upperBound] = range;
|
|
141
|
+
return featureValue >= lowerBound && featureValue <= upperBound;
|
|
142
|
+
};
|
|
143
|
+
return makeIntervalComplete(filterValues).some(checkRange);
|
|
144
|
+
}
|
|
145
|
+
function filterTime(filterValues, featureValue) {
|
|
146
|
+
const featureValueAsTimestamp = new Date(featureValue).getTime();
|
|
147
|
+
if (isFinite(featureValueAsTimestamp)) {
|
|
148
|
+
return filterBetween(filterValues, featureValueAsTimestamp);
|
|
149
|
+
} else {
|
|
150
|
+
throw new Error(`Column used to filter by time isn't well formatted.`);
|
|
159
151
|
}
|
|
160
|
-
return true;
|
|
161
152
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
const
|
|
153
|
+
// FilterTypes.CLOSED_OPEN
|
|
154
|
+
function filterClosedOpen(filterValues, featureValue) {
|
|
155
|
+
const checkRange = range => {
|
|
156
|
+
const [lowerBound, upperBound] = range;
|
|
157
|
+
return featureValue >= lowerBound && featureValue < upperBound;
|
|
158
|
+
};
|
|
159
|
+
return makeIntervalComplete(filterValues).some(checkRange);
|
|
160
|
+
}
|
|
161
|
+
// FilterTypes.STRING_SEARCH
|
|
162
|
+
function filterStringSearch(filterValues, featureValue, params = {}) {
|
|
163
|
+
const normalizedFeatureValue = normalize(featureValue, params);
|
|
164
|
+
const stringRegExp = params.useRegExp ? filterValues : filterValues.map(filterValue => {
|
|
165
|
+
let stringRegExp = escapeRegExp(normalize(filterValue, params));
|
|
166
|
+
if (params.mustStart) stringRegExp = `^${stringRegExp}`;
|
|
167
|
+
if (params.mustEnd) stringRegExp = `${stringRegExp}$`;
|
|
168
|
+
return stringRegExp;
|
|
169
|
+
});
|
|
170
|
+
const regex = new RegExp(stringRegExp.join('|'), params.caseSensitive ? 'g' : 'gi');
|
|
171
|
+
return !!normalizedFeatureValue.match(regex);
|
|
172
|
+
}
|
|
173
|
+
// Aux
|
|
174
|
+
const specialCharRegExp = /[.*+?^${}()|[\]\\]/g;
|
|
175
|
+
const normalizeRegExp = /(?:[\^`\xA8\xAF\xB4\xB7\xB8\u02B0-\u034E\u0350-\u0357\u035D-\u0362\u0374\u0375\u037A\u0384\u0385\u0483-\u0487\u0559\u0591-\u05A1\u05A3-\u05BD\u05BF\u05C1\u05C2\u05C4\u064B-\u0652\u0657\u0658\u06DF\u06E0\u06E5\u06E6\u06EA-\u06EC\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F5\u0818\u0819\u0898-\u089F\u08C9-\u08D2\u08E3-\u08FE\u093C\u094D\u0951-\u0954\u0971\u09BC\u09CD\u0A3C\u0A4D\u0ABC\u0ACD\u0AFD-\u0AFF\u0B3C\u0B4D\u0B55\u0BCD\u0C3C\u0C4D\u0CBC\u0CCD\u0D3B\u0D3C\u0D4D\u0DCA\u0E3A\u0E47-\u0E4C\u0E4E\u0EBA\u0EC8-\u0ECC\u0F18\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F82-\u0F84\u0F86\u0F87\u0FC6\u1037\u1039\u103A\u1063\u1064\u1069-\u106D\u1087-\u108D\u108F\u109A\u109B\u135D-\u135F\u1714\u1715\u1734\u17C9-\u17D3\u17DD\u1939-\u193B\u1A60\u1A75-\u1A7C\u1A7F\u1AB0-\u1ABE\u1AC1-\u1ACB\u1B34\u1B44\u1B6B-\u1B73\u1BAA\u1BAB\u1BE6\u1BF2\u1BF3\u1C36\u1C37\u1C78-\u1C7D\u1CD0-\u1CE8\u1CED\u1CF4\u1CF7-\u1CF9\u1D2C-\u1D6A\u1DC4-\u1DCF\u1DF5-\u1DFF\u1FBD\u1FBF-\u1FC1\u1FCD-\u1FCF\u1FDD-\u1FDF\u1FED-\u1FEF\u1FFD\u1FFE\u2CEF-\u2CF1\u2E2F\u302A-\u302F\u3099-\u309C\u30FC\uA66F\uA67C\uA67D\uA67F\uA69C\uA69D\uA6F0\uA6F1\uA700-\uA721\uA788-\uA78A\uA7F8\uA7F9\uA806\uA82C\uA8C4\uA8E0-\uA8F1\uA92B-\uA92E\uA953\uA9B3\uA9C0\uA9E5\uAA7B-\uAA7D\uAABF-\uAAC2\uAAF6\uAB5B-\uAB5F\uAB69-\uAB6B\uABEC\uABED\uFB1E\uFE20-\uFE2F\uFF3E\uFF40\uFF70\uFF9E\uFF9F\uFFE3]|\uD800\uDEE0|\uD801[\uDF80-\uDF85\uDF87-\uDFB0\uDFB2-\uDFBA]|\uD802[\uDE38-\uDE3A\uDE3F\uDEE5\uDEE6]|\uD803[\uDD22-\uDD27\uDD4E\uDD69-\uDD6D\uDEFD-\uDEFF\uDF46-\uDF50\uDF82-\uDF85]|\uD804[\uDC46\uDC70\uDCB9\uDCBA\uDD33\uDD34\uDD73\uDDC0\uDDCA-\uDDCC\uDE35\uDE36\uDEE9\uDEEA\uDF3B\uDF3C\uDF4D\uDF66-\uDF6C\uDF70-\uDF74\uDFCE-\uDFD0\uDFD2\uDFD3\uDFE1\uDFE2]|\uD805[\uDC42\uDC46\uDCC2\uDCC3\uDDBF\uDDC0\uDE3F\uDEB6\uDEB7\uDF2B]|\uD806[\uDC39\uDC3A\uDD3D\uDD3E\uDD43\uDDE0\uDE34\uDE47\uDE99]|\uD807[\uDC3F\uDD42\uDD44\uDD45\uDD97\uDF41\uDF42\uDF5A]|\uD80D[\uDC47-\uDC55]|\uD818\uDD2F|\uD81A[\uDEF0-\uDEF4\uDF30-\uDF36]|\uD81B[\uDD6B\uDD6C\uDF8F-\uDF9F\uDFF0\uDFF1]|\uD82B[\uDFF0-\uDFF3\uDFF5-\uDFFB\uDFFD\uDFFE]|\uD833[\uDF00-\uDF2D\uDF30-\uDF46]|\uD834[\uDD67-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD]|\uD838[\uDC30-\uDC6D\uDD30-\uDD36\uDEAE\uDEEC-\uDEEF]|\uD839[\uDDEE\uDDEF]|\uD83A[\uDCD0-\uDCD6\uDD44-\uDD46\uDD48-\uDD4A])/g;
|
|
176
|
+
function escapeRegExp(value) {
|
|
177
|
+
return value.replace(specialCharRegExp, '\\$&');
|
|
178
|
+
}
|
|
179
|
+
function normalize(data, params) {
|
|
180
|
+
let normalizedData = String(data);
|
|
181
|
+
if (!params.keepSpecialCharacters) normalizedData = normalizedData.normalize('NFD').replace(normalizeRegExp, '');
|
|
182
|
+
return normalizedData;
|
|
183
|
+
}
|
|
166
184
|
|
|
185
|
+
const LOGICAL_OPERATOR_METHODS = {
|
|
186
|
+
and: 'every',
|
|
187
|
+
or: 'some'
|
|
188
|
+
};
|
|
189
|
+
function passesFilter(columns, filters, feature, filtersLogicalOperator) {
|
|
190
|
+
const method = LOGICAL_OPERATOR_METHODS[filtersLogicalOperator];
|
|
191
|
+
return columns[method](column => {
|
|
192
|
+
const columnFilters = filters[column];
|
|
193
|
+
const columnFilterTypes = Object.keys(columnFilters);
|
|
194
|
+
if (!feature || feature[column] === null || feature[column] === undefined) {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
return columnFilterTypes.every(filter => {
|
|
198
|
+
const filterFunction = filterFunctions[filter];
|
|
199
|
+
if (!filterFunction) {
|
|
200
|
+
throw new Error(`"${filter}" filter is not implemented.`);
|
|
201
|
+
}
|
|
202
|
+
return filterFunction(columnFilters[filter].values, feature[column], columnFilters[filter].params);
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
}
|
|
167
206
|
/**
|
|
168
|
-
*
|
|
169
|
-
*
|
|
207
|
+
* @internal
|
|
208
|
+
* @privateRemarks Exported for use in @deck.gl/carto's getDataFilterExtensionProps.
|
|
170
209
|
*/
|
|
171
|
-
function
|
|
172
|
-
|
|
173
|
-
type,
|
|
174
|
-
|
|
175
|
-
owner
|
|
210
|
+
function _buildFeatureFilter({
|
|
211
|
+
filters = {},
|
|
212
|
+
type = 'boolean',
|
|
213
|
+
filtersLogicalOperator = 'and'
|
|
176
214
|
}) {
|
|
177
|
-
|
|
178
|
-
|
|
215
|
+
const columns = Object.keys(filters);
|
|
216
|
+
if (!columns.length) {
|
|
217
|
+
return () => type === 'number' ? 1 : true;
|
|
179
218
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
219
|
+
return feature => {
|
|
220
|
+
const f = feature.properties || feature;
|
|
221
|
+
const featurePassesFilter = passesFilter(columns, filters, f, filtersLogicalOperator);
|
|
222
|
+
return type === 'number' ? Number(featurePassesFilter) : featurePassesFilter;
|
|
183
223
|
};
|
|
184
|
-
filters[column][type] = filter;
|
|
185
|
-
return filters;
|
|
186
224
|
}
|
|
187
225
|
/**
|
|
188
|
-
*
|
|
189
|
-
*
|
|
190
|
-
* `column` and `owner` are specified, then only filters for that column
|
|
191
|
-
* associated with the owner are removed.
|
|
226
|
+
* Apply certain filters to a collection of features.
|
|
227
|
+
* @internal
|
|
192
228
|
*/
|
|
193
|
-
function
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
if (!filter) {
|
|
199
|
-
return filters;
|
|
200
|
-
}
|
|
201
|
-
if (owner) {
|
|
202
|
-
for (const type of Object.values(FilterType)) {
|
|
203
|
-
var _filter$type;
|
|
204
|
-
if (owner === ((_filter$type = filter[type]) == null ? void 0 : _filter$type.owner)) {
|
|
205
|
-
delete filter[type];
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
if (!owner || isEmptyObject(filter)) {
|
|
210
|
-
delete filters[column];
|
|
211
|
-
}
|
|
212
|
-
return filters;
|
|
229
|
+
function applyFilters(features, filters, filtersLogicalOperator) {
|
|
230
|
+
return Object.keys(filters).length ? features.filter(_buildFeatureFilter({
|
|
231
|
+
filters,
|
|
232
|
+
filtersLogicalOperator
|
|
233
|
+
})) : features;
|
|
213
234
|
}
|
|
214
235
|
/**
|
|
215
|
-
*
|
|
236
|
+
* Binary.
|
|
237
|
+
* @internal
|
|
216
238
|
*/
|
|
217
|
-
function
|
|
218
|
-
|
|
219
|
-
delete filters[column];
|
|
220
|
-
}
|
|
221
|
-
return filters;
|
|
222
|
-
}
|
|
223
|
-
function hasFilter(filters, {
|
|
224
|
-
column,
|
|
225
|
-
owner
|
|
239
|
+
function buildBinaryFeatureFilter({
|
|
240
|
+
filters = {}
|
|
226
241
|
}) {
|
|
227
|
-
const
|
|
228
|
-
if (!
|
|
229
|
-
return
|
|
230
|
-
}
|
|
231
|
-
if (!owner) {
|
|
232
|
-
return true;
|
|
233
|
-
}
|
|
234
|
-
for (const type of Object.values(FilterType)) {
|
|
235
|
-
var _filter$type2;
|
|
236
|
-
if (owner === ((_filter$type2 = filter[type]) == null ? void 0 : _filter$type2.owner)) {
|
|
237
|
-
return true;
|
|
238
|
-
}
|
|
242
|
+
const columns = Object.keys(filters);
|
|
243
|
+
if (!columns.length) {
|
|
244
|
+
return () => 1;
|
|
239
245
|
}
|
|
240
|
-
return
|
|
246
|
+
return (featureIdIdx, binaryData) => passesFilterUsingBinary(columns, filters, featureIdIdx, binaryData);
|
|
241
247
|
}
|
|
242
|
-
function
|
|
243
|
-
column
|
|
244
|
-
type,
|
|
245
|
-
owner
|
|
248
|
+
function getValueFromNumericProps(featureIdIdx, binaryData, {
|
|
249
|
+
column
|
|
246
250
|
}) {
|
|
247
|
-
var
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
+
var _binaryData$numericPr;
|
|
252
|
+
return (_binaryData$numericPr = binaryData.numericProps) == null || (_binaryData$numericPr = _binaryData$numericPr[column]) == null ? void 0 : _binaryData$numericPr.value[featureIdIdx];
|
|
253
|
+
}
|
|
254
|
+
function getValueFromProperties(featureIdIdx, binaryData, {
|
|
255
|
+
column
|
|
256
|
+
}) {
|
|
257
|
+
var _binaryData$propertie;
|
|
258
|
+
const propertyIdx = binaryData.featureIds.value[featureIdIdx];
|
|
259
|
+
return (_binaryData$propertie = binaryData.properties[propertyIdx]) == null ? void 0 : _binaryData$propertie[column];
|
|
260
|
+
}
|
|
261
|
+
const GET_VALUE_BY_BINARY_PROP = {
|
|
262
|
+
properties: getValueFromProperties,
|
|
263
|
+
numericProps: getValueFromNumericProps
|
|
264
|
+
};
|
|
265
|
+
function getBinaryPropertyByFilterValues(filterValues) {
|
|
266
|
+
return typeof filterValues.flat()[0] === 'string' ? 'properties' : 'numericProps';
|
|
267
|
+
}
|
|
268
|
+
function getFeatureValue(featureIdIdx, binaryData, filter) {
|
|
269
|
+
const {
|
|
270
|
+
column,
|
|
271
|
+
values
|
|
272
|
+
} = filter;
|
|
273
|
+
const binaryProp = getBinaryPropertyByFilterValues(values);
|
|
274
|
+
const getFeatureValueFn = GET_VALUE_BY_BINARY_PROP[binaryProp];
|
|
275
|
+
return getFeatureValueFn(featureIdIdx, binaryData, {
|
|
276
|
+
column
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
function passesFilterUsingBinary(columns, filters, featureIdIdx, binaryData) {
|
|
280
|
+
return columns.every(column => {
|
|
281
|
+
const columnFilters = filters[column];
|
|
282
|
+
return Object.entries(columnFilters).every(([type, {
|
|
283
|
+
values
|
|
284
|
+
}]) => {
|
|
285
|
+
const filterFn = filterFunctions[type];
|
|
286
|
+
if (!filterFn) {
|
|
287
|
+
throw new Error(`"${type}" filter is not implemented.`);
|
|
288
|
+
}
|
|
289
|
+
if (!values) return 0;
|
|
290
|
+
const featureValue = getFeatureValue(featureIdIdx, binaryData, {
|
|
291
|
+
type: type,
|
|
292
|
+
column,
|
|
293
|
+
values
|
|
294
|
+
});
|
|
295
|
+
if (featureValue === undefined || featureValue === null) return 0;
|
|
296
|
+
return filterFn(values, featureValue);
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function geojsonFeatures({
|
|
302
|
+
geojson,
|
|
303
|
+
spatialFilter,
|
|
304
|
+
uniqueIdProperty
|
|
305
|
+
}) {
|
|
306
|
+
let uniqueIdx = 0;
|
|
307
|
+
const map = new Map();
|
|
308
|
+
if (!spatialFilter) {
|
|
309
|
+
return [];
|
|
251
310
|
}
|
|
252
|
-
|
|
253
|
-
|
|
311
|
+
for (const feature of geojson.features) {
|
|
312
|
+
const uniqueId = uniqueIdProperty ? feature.properties[uniqueIdProperty] : ++uniqueIdx;
|
|
313
|
+
if (!map.has(uniqueId) && intersects(spatialFilter, feature)) {
|
|
314
|
+
map.set(uniqueId, feature.properties);
|
|
315
|
+
}
|
|
254
316
|
}
|
|
255
|
-
return
|
|
317
|
+
return Array.from(map.values());
|
|
256
318
|
}
|
|
257
319
|
|
|
320
|
+
// math.gl
|
|
321
|
+
// SPDX-License-Identifier: MIT
|
|
322
|
+
// Copyright (c) vis.gl contributors
|
|
323
|
+
const DEFAULT_CONFIG = {
|
|
324
|
+
EPSILON: 1e-12,
|
|
325
|
+
debug: false,
|
|
326
|
+
precision: 4,
|
|
327
|
+
printTypes: false,
|
|
328
|
+
printDegrees: false,
|
|
329
|
+
printRowMajor: true,
|
|
330
|
+
_cartographicRadians: false
|
|
331
|
+
};
|
|
332
|
+
// Configuration is truly global as of v3.6 to ensure single config even if multiple copies of math.gl
|
|
333
|
+
// Multiple copies of config can be quite tricky to debug...
|
|
334
|
+
globalThis.mathgl = globalThis.mathgl || {
|
|
335
|
+
config: {
|
|
336
|
+
...DEFAULT_CONFIG
|
|
337
|
+
}
|
|
338
|
+
};
|
|
258
339
|
/**
|
|
259
|
-
*
|
|
260
|
-
*
|
|
261
|
-
*
|
|
262
|
-
*
|
|
263
|
-
*
|
|
264
|
-
* If the viewport extends beyond longitude range [-180, +180], the polygon
|
|
265
|
-
* may be reformatted for compatibility with CARTO APIs.
|
|
340
|
+
* Check if value is an "array"
|
|
341
|
+
* Returns `true` if value is either an array or a typed array
|
|
342
|
+
* Note: returns `false` for `ArrayBuffer` and `DataView` instances
|
|
343
|
+
* @note isTypedArray and isNumericArray are often more useful in TypeScript
|
|
266
344
|
*/
|
|
267
|
-
function
|
|
268
|
-
|
|
269
|
-
|
|
345
|
+
function isArray(value) {
|
|
346
|
+
return Array.isArray(value) || ArrayBuffer.isView(value) && !(value instanceof DataView);
|
|
347
|
+
}
|
|
348
|
+
function lerp(a, b, t) {
|
|
349
|
+
if (isArray(a)) {
|
|
350
|
+
return a.map((ai, i) => lerp(ai, b[i], t));
|
|
351
|
+
}
|
|
352
|
+
return t * b + (1 - t) * a;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Replacement for the external assert method to reduce bundle size
|
|
356
|
+
// Note: We don't use the second "message" argument in calling code,
|
|
357
|
+
// so no need to support it here
|
|
358
|
+
function assert$1(condition, message) {
|
|
359
|
+
if (!condition) {
|
|
360
|
+
throw new Error(message || '@math.gl/web-mercator: assertion failed.');
|
|
270
361
|
}
|
|
271
|
-
return createPolygonSpatialFilter(bboxPolygon(viewport).geometry);
|
|
272
362
|
}
|
|
363
|
+
|
|
364
|
+
// TODO - THE UTILITIES IN THIS FILE SHOULD BE IMPORTED FROM WEB-MERCATOR-VIEWPORT MODULE
|
|
365
|
+
// CONSTANTS
|
|
366
|
+
const PI = Math.PI;
|
|
367
|
+
const PI_4 = PI / 4;
|
|
368
|
+
const DEGREES_TO_RADIANS = PI / 180;
|
|
369
|
+
const RADIANS_TO_DEGREES = 180 / PI;
|
|
370
|
+
const TILE_SIZE = 512;
|
|
273
371
|
/**
|
|
274
|
-
*
|
|
275
|
-
*
|
|
276
|
-
*
|
|
277
|
-
*
|
|
372
|
+
* Project [lng,lat] on sphere onto [x,y] on 512*512 Mercator Zoom 0 tile.
|
|
373
|
+
* Performs the nonlinear part of the web mercator projection.
|
|
374
|
+
* Remaining projection is done with 4x4 matrices which also handles
|
|
375
|
+
* perspective.
|
|
376
|
+
*
|
|
377
|
+
* @param lngLat - [lng, lat] coordinates
|
|
378
|
+
* Specifies a point on the sphere to project onto the map.
|
|
379
|
+
* @return [x,y] coordinates.
|
|
278
380
|
*/
|
|
279
|
-
function
|
|
280
|
-
|
|
381
|
+
function lngLatToWorld(lngLat) {
|
|
382
|
+
const [lng, lat] = lngLat;
|
|
383
|
+
assert$1(Number.isFinite(lng));
|
|
384
|
+
assert$1(Number.isFinite(lat) && lat >= -90 && lat <= 90, 'invalid latitude');
|
|
385
|
+
const lambda2 = lng * DEGREES_TO_RADIANS;
|
|
386
|
+
const phi2 = lat * DEGREES_TO_RADIANS;
|
|
387
|
+
const x = TILE_SIZE * (lambda2 + PI) / (2 * PI);
|
|
388
|
+
const y = TILE_SIZE * (PI + Math.log(Math.tan(PI_4 + phi2 * 0.5))) / (2 * PI);
|
|
389
|
+
return [x, y];
|
|
281
390
|
}
|
|
282
391
|
/**
|
|
283
|
-
*
|
|
284
|
-
* In this case the spatial filter parameter for widget calculation is removed.
|
|
392
|
+
* Unproject world point [x,y] on map onto {lat, lon} on sphere
|
|
285
393
|
*
|
|
286
|
-
* @
|
|
394
|
+
* @param xy - array with [x,y] members
|
|
395
|
+
* representing point on projected map plane
|
|
396
|
+
* @return - array with [x,y] of point on sphere.
|
|
397
|
+
* Has toArray method if you need a GeoJSON Array.
|
|
398
|
+
* Per cartographic tradition, lat and lon are specified as degrees.
|
|
287
399
|
*/
|
|
288
|
-
function
|
|
289
|
-
const [
|
|
290
|
-
|
|
400
|
+
function worldToLngLat(xy) {
|
|
401
|
+
const [x, y] = xy;
|
|
402
|
+
const lambda2 = x / TILE_SIZE * (2 * PI) - PI;
|
|
403
|
+
const phi2 = 2 * (Math.atan(Math.exp(y / TILE_SIZE * (2 * PI) - PI)) - PI_4);
|
|
404
|
+
return [lambda2 * RADIANS_TO_DEGREES, phi2 * RADIANS_TO_DEGREES];
|
|
291
405
|
}
|
|
406
|
+
|
|
407
|
+
const TRANSFORM_FN$1 = {
|
|
408
|
+
Point: transformPoint$1,
|
|
409
|
+
MultiPoint: transformMultiPoint$1,
|
|
410
|
+
LineString: transformLineString$1,
|
|
411
|
+
MultiLineString: transformMultiLineString$1,
|
|
412
|
+
Polygon: transformPolygon$1,
|
|
413
|
+
MultiPolygon: transformMultiPolygon$1
|
|
414
|
+
};
|
|
292
415
|
/**
|
|
293
|
-
*
|
|
294
|
-
*
|
|
295
|
-
* back to the valid range and unioned to the polygons inide that range.
|
|
296
|
-
*
|
|
297
|
-
* It results in a Polygon or MultiPolygon strictly inside the validity range.
|
|
416
|
+
* Transform WGS84 coordinates to tile coords.
|
|
417
|
+
* 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)
|
|
298
418
|
*
|
|
299
|
-
* @
|
|
419
|
+
* @param geometry - any valid geojson geometry
|
|
420
|
+
* @param bbox - geojson bbox
|
|
300
421
|
*/
|
|
301
|
-
function
|
|
302
|
-
const
|
|
303
|
-
const
|
|
304
|
-
const
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
const worldWestClip = _clean(bboxClip(geometryTxWest, WORLD).geometry);
|
|
309
|
-
if (worldWestClip) {
|
|
310
|
-
const collection = featureCollection([feature(result), feature(worldWestClip)]);
|
|
311
|
-
const merged = union(collection);
|
|
312
|
-
result = merged ? _clean(merged.geometry) : result;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
if (result && geometryTxEast) {
|
|
316
|
-
const worldEastClip = _clean(bboxClip(geometryTxEast, WORLD).geometry);
|
|
317
|
-
if (worldEastClip) {
|
|
318
|
-
const collection = featureCollection([feature(result), feature(worldEastClip)]);
|
|
319
|
-
const merged = union(collection);
|
|
320
|
-
result = merged ? _clean(merged.geometry) : result;
|
|
321
|
-
}
|
|
422
|
+
function transformToTileCoords(geometry, bbox) {
|
|
423
|
+
const [west, south, east, north] = bbox;
|
|
424
|
+
const nw = projectFlat([west, north]);
|
|
425
|
+
const se = projectFlat([east, south]);
|
|
426
|
+
const projectedBbox = [nw, se];
|
|
427
|
+
if (geometry.type === 'GeometryCollection') {
|
|
428
|
+
throw new Error('Unsupported geometry type GeometryCollection');
|
|
322
429
|
}
|
|
323
|
-
|
|
430
|
+
const transformFn = TRANSFORM_FN$1[geometry.type];
|
|
431
|
+
const coordinates = transformFn(geometry.coordinates, projectedBbox);
|
|
432
|
+
return _extends({}, geometry, {
|
|
433
|
+
coordinates
|
|
434
|
+
});
|
|
324
435
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
const
|
|
328
|
-
return
|
|
436
|
+
function transformPoint$1([pointX, pointY], [nw, se]) {
|
|
437
|
+
const x = inverseLerp(nw[0], se[0], pointX);
|
|
438
|
+
const y = inverseLerp(nw[1], se[1], pointY);
|
|
439
|
+
return [x, y];
|
|
329
440
|
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
const coords = ccc.map(_cleanPolygonCoords).filter(cc => cc);
|
|
333
|
-
return coords.length > 0 ? coords : null;
|
|
441
|
+
function getPoints$1(geometry, bbox) {
|
|
442
|
+
return geometry.map(g => transformPoint$1(projectFlat(g), bbox));
|
|
334
443
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
if (!geometry) {
|
|
338
|
-
return null;
|
|
339
|
-
}
|
|
340
|
-
if (_isPolygon(geometry)) {
|
|
341
|
-
const coords = _cleanPolygonCoords(geometry.coordinates);
|
|
342
|
-
return coords ? polygon(coords).geometry : null;
|
|
343
|
-
}
|
|
344
|
-
if (_isMultiPolygon(geometry)) {
|
|
345
|
-
const coords = _cleanMultiPolygonCoords(geometry.coordinates);
|
|
346
|
-
return coords ? multiPolygon(coords).geometry : null;
|
|
347
|
-
}
|
|
348
|
-
return null;
|
|
444
|
+
function transformMultiPoint$1(multiPoint, bbox) {
|
|
445
|
+
return getPoints$1(multiPoint, bbox);
|
|
349
446
|
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
return cc.map(c => [c[0] + distance, c[1]]);
|
|
447
|
+
function transformLineString$1(line, bbox) {
|
|
448
|
+
return getPoints$1(line, bbox);
|
|
353
449
|
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
return ccc.map(cc => _txContourCoords(cc, distance));
|
|
357
|
-
}
|
|
358
|
-
/** @internalRemarks Source: @carto/react-core */
|
|
359
|
-
function _txMultiPolygonCoords(cccc, distance) {
|
|
360
|
-
return cccc.map(ccc => _txPolygonCoords(ccc, distance));
|
|
361
|
-
}
|
|
362
|
-
/** @internalRemarks Source: @carto/react-core */
|
|
363
|
-
function _tx(geometry, distance) {
|
|
364
|
-
if (geometry && getType(geometry) === 'Polygon') {
|
|
365
|
-
const coords = _txPolygonCoords(geometry.coordinates, distance);
|
|
366
|
-
return polygon(coords).geometry;
|
|
367
|
-
} else if (geometry && getType(geometry) === 'MultiPolygon') {
|
|
368
|
-
const coords = _txMultiPolygonCoords(geometry.coordinates, distance);
|
|
369
|
-
return multiPolygon(coords).geometry;
|
|
370
|
-
} else {
|
|
371
|
-
return null;
|
|
372
|
-
}
|
|
450
|
+
function transformMultiLineString$1(multiLineString, bbox) {
|
|
451
|
+
return multiLineString.map(lineString => transformLineString$1(lineString, bbox));
|
|
373
452
|
}
|
|
374
|
-
function
|
|
375
|
-
return
|
|
453
|
+
function transformPolygon$1(polygon, bbox) {
|
|
454
|
+
return polygon.map(polygonRing => getPoints$1(polygonRing, bbox));
|
|
376
455
|
}
|
|
377
|
-
function
|
|
378
|
-
return
|
|
456
|
+
function transformMultiPolygon$1(multiPolygon, bbox) {
|
|
457
|
+
return multiPolygon.map(polygon => transformPolygon$1(polygon, bbox));
|
|
379
458
|
}
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
return _extends = Object.assign ? Object.assign.bind() : function (n) {
|
|
383
|
-
for (var e = 1; e < arguments.length; e++) {
|
|
384
|
-
var t = arguments[e];
|
|
385
|
-
for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
|
|
386
|
-
}
|
|
387
|
-
return n;
|
|
388
|
-
}, _extends.apply(null, arguments);
|
|
459
|
+
function projectFlat(xyz) {
|
|
460
|
+
return lngLatToWorld(xyz);
|
|
389
461
|
}
|
|
390
|
-
function
|
|
391
|
-
|
|
392
|
-
var t = {};
|
|
393
|
-
for (var n in r) if ({}.hasOwnProperty.call(r, n)) {
|
|
394
|
-
if (e.includes(n)) continue;
|
|
395
|
-
t[n] = r[n];
|
|
396
|
-
}
|
|
397
|
-
return t;
|
|
462
|
+
function inverseLerp(a, b, x) {
|
|
463
|
+
return (x - a) / (b - a);
|
|
398
464
|
}
|
|
399
465
|
|
|
466
|
+
const TRANSFORM_FN = {
|
|
467
|
+
Point: transformPoint,
|
|
468
|
+
MultiPoint: transformMultiPoint,
|
|
469
|
+
LineString: transformLineString,
|
|
470
|
+
MultiLineString: transformMultiLineString,
|
|
471
|
+
Polygon: transformPolygon,
|
|
472
|
+
MultiPolygon: transformMultiPolygon
|
|
473
|
+
};
|
|
400
474
|
/**
|
|
401
|
-
*
|
|
402
|
-
*
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
const V3_MINOR_VERSION = '3.4';
|
|
406
|
-
/** @internalRemarks Source: @carto/constants, @deck.gl/carto */
|
|
407
|
-
const DEFAULT_GEO_COLUMN = 'geom';
|
|
408
|
-
/**
|
|
409
|
-
* Fastly default limit is 8192; leave some padding.
|
|
410
|
-
* @internalRemarks Source: @deck.gl/carto
|
|
411
|
-
*/
|
|
412
|
-
const DEFAULT_MAX_LENGTH_URL = 7000;
|
|
413
|
-
/** @internalRemarks Source: @deck.gl/carto */
|
|
414
|
-
const DEFAULT_TILE_RESOLUTION = 0.5;
|
|
415
|
-
/**
|
|
416
|
-
* @internalRemarks Source: @deck.gl/carto
|
|
417
|
-
* @internal
|
|
418
|
-
*/
|
|
419
|
-
const DEFAULT_AGGREGATION_RES_LEVEL_H3 = 4;
|
|
420
|
-
/**
|
|
421
|
-
* @internalRemarks Source: @deck.gl/carto
|
|
422
|
-
* @internal
|
|
475
|
+
* Transform tile coords to WGS84 coordinates.
|
|
476
|
+
*
|
|
477
|
+
* @param geometry - any valid geojson geometry
|
|
478
|
+
* @param bbox - geojson bbox
|
|
423
479
|
*/
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
480
|
+
function transformTileCoordsToWGS84(geometry, bbox) {
|
|
481
|
+
const [west, south, east, north] = bbox;
|
|
482
|
+
const nw = lngLatToWorld([west, north]);
|
|
483
|
+
const se = lngLatToWorld([east, south]);
|
|
484
|
+
const projectedBbox = [nw, se];
|
|
485
|
+
if (geometry.type === 'GeometryCollection') {
|
|
486
|
+
throw new Error('Unsupported geometry type GeometryCollection');
|
|
487
|
+
}
|
|
488
|
+
const transformFn = TRANSFORM_FN[geometry.type];
|
|
489
|
+
const coordinates = transformFn(geometry.coordinates, projectedBbox);
|
|
490
|
+
return _extends({}, geometry, {
|
|
491
|
+
coordinates
|
|
492
|
+
});
|
|
431
493
|
}
|
|
432
|
-
function
|
|
433
|
-
|
|
494
|
+
function transformPoint([pointX, pointY], [nw, se]) {
|
|
495
|
+
const x = lerp(nw[0], se[0], pointX);
|
|
496
|
+
const y = lerp(nw[1], se[1], pointY);
|
|
497
|
+
return worldToLngLat([x, y]);
|
|
434
498
|
}
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
apiBaseUrl,
|
|
438
|
-
cartoMapId
|
|
439
|
-
}) {
|
|
440
|
-
return buildV3Path(apiBaseUrl, 'v3', 'maps', 'public', cartoMapId);
|
|
499
|
+
function getPoints(geometry, bbox) {
|
|
500
|
+
return geometry.map(g => transformPoint(g, bbox));
|
|
441
501
|
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
attribute,
|
|
445
|
-
apiBaseUrl,
|
|
446
|
-
connectionName,
|
|
447
|
-
source,
|
|
448
|
-
type
|
|
449
|
-
}) {
|
|
450
|
-
if (type === 'query') {
|
|
451
|
-
return buildV3Path(apiBaseUrl, 'v3', 'stats', connectionName, attribute);
|
|
452
|
-
}
|
|
453
|
-
// type === 'table'
|
|
454
|
-
return buildV3Path(apiBaseUrl, 'v3', 'stats', connectionName, source, attribute);
|
|
502
|
+
function transformMultiPoint(multiPoint, bbox) {
|
|
503
|
+
return getPoints(multiPoint, bbox);
|
|
455
504
|
}
|
|
456
|
-
function
|
|
457
|
-
|
|
458
|
-
connectionName,
|
|
459
|
-
endpoint
|
|
460
|
-
}) {
|
|
461
|
-
return buildV3Path(apiBaseUrl, 'v3', 'maps', connectionName, endpoint);
|
|
505
|
+
function transformLineString(line, bbox) {
|
|
506
|
+
return getPoints(line, bbox);
|
|
462
507
|
}
|
|
463
|
-
function
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
return
|
|
508
|
+
function transformMultiLineString(multiLineString, bbox) {
|
|
509
|
+
return multiLineString.map(lineString => transformLineString(lineString, bbox));
|
|
510
|
+
}
|
|
511
|
+
function transformPolygon(polygon, bbox) {
|
|
512
|
+
return polygon.map(polygonRing => getPoints(polygonRing, bbox));
|
|
513
|
+
}
|
|
514
|
+
function transformMultiPolygon(multiPolygon, bbox) {
|
|
515
|
+
return multiPolygon.map(polygon => transformPolygon(polygon, bbox));
|
|
468
516
|
}
|
|
469
517
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
if (
|
|
483
|
-
|
|
484
|
-
if (response.status === 400) {
|
|
485
|
-
responseString += 'Bad request';
|
|
486
|
-
} else if (response.status === 401 || response.status === 403) {
|
|
487
|
-
responseString += 'Unauthorized access';
|
|
488
|
-
} else if (response.status === 404) {
|
|
489
|
-
responseString += 'Not found';
|
|
490
|
-
} else {
|
|
491
|
-
responseString += 'Error';
|
|
492
|
-
}
|
|
493
|
-
responseString += ` (${response.status}):`;
|
|
518
|
+
const FEATURE_GEOM_PROPERTY = '__geomValue';
|
|
519
|
+
function tileFeaturesGeometries({
|
|
520
|
+
tiles,
|
|
521
|
+
tileFormat,
|
|
522
|
+
spatialFilter,
|
|
523
|
+
uniqueIdProperty,
|
|
524
|
+
options
|
|
525
|
+
}) {
|
|
526
|
+
const map = new Map();
|
|
527
|
+
for (const tile of tiles) {
|
|
528
|
+
// Discard if it's not a visible tile (only check false value, not undefined)
|
|
529
|
+
// or tile has not data
|
|
530
|
+
if (tile.isVisible === false || !tile.data) {
|
|
531
|
+
continue;
|
|
494
532
|
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
533
|
+
const bbox = [tile.bbox.west, tile.bbox.south, tile.bbox.east, tile.bbox.north];
|
|
534
|
+
const bboxToGeom = bboxPolygon(bbox);
|
|
535
|
+
const tileIsFullyVisible = booleanWithin(bboxToGeom, spatialFilter);
|
|
536
|
+
// Clip the geometry to intersect with the tile
|
|
537
|
+
const spatialFilterFeature = {
|
|
538
|
+
type: 'Feature',
|
|
539
|
+
geometry: spatialFilter,
|
|
540
|
+
properties: {}
|
|
541
|
+
};
|
|
542
|
+
const clippedGeometryToIntersect = intersect(featureCollection([bboxToGeom, spatialFilterFeature]));
|
|
543
|
+
if (!clippedGeometryToIntersect) {
|
|
544
|
+
continue;
|
|
501
545
|
}
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
546
|
+
// We assume that MVT tileFormat uses local coordinates so we transform the geometry to intersect to tile coordinates [0..1],
|
|
547
|
+
// while in the case of 'geojson' or binary, the geometries are already in WGS84
|
|
548
|
+
const transformedGeometryToIntersect = tileFormat === TileFormat.MVT ? transformToTileCoords(clippedGeometryToIntersect.geometry, bbox) : clippedGeometryToIntersect.geometry;
|
|
549
|
+
createIndicesForPoints(tile.data.points);
|
|
550
|
+
calculateFeatures({
|
|
551
|
+
map,
|
|
552
|
+
tileIsFullyVisible,
|
|
553
|
+
geometryIntersection: transformedGeometryToIntersect,
|
|
554
|
+
data: tile.data.points,
|
|
555
|
+
type: 'Point',
|
|
556
|
+
bbox,
|
|
557
|
+
tileFormat,
|
|
558
|
+
uniqueIdProperty,
|
|
559
|
+
options
|
|
560
|
+
});
|
|
561
|
+
calculateFeatures({
|
|
562
|
+
map,
|
|
563
|
+
tileIsFullyVisible,
|
|
564
|
+
geometryIntersection: transformedGeometryToIntersect,
|
|
565
|
+
data: tile.data.lines,
|
|
566
|
+
type: 'LineString',
|
|
567
|
+
bbox,
|
|
568
|
+
tileFormat,
|
|
569
|
+
uniqueIdProperty,
|
|
570
|
+
options
|
|
571
|
+
});
|
|
572
|
+
calculateFeatures({
|
|
573
|
+
map,
|
|
574
|
+
tileIsFullyVisible,
|
|
575
|
+
geometryIntersection: transformedGeometryToIntersect,
|
|
576
|
+
data: tile.data.polygons,
|
|
577
|
+
type: 'Polygon',
|
|
578
|
+
bbox,
|
|
579
|
+
tileFormat,
|
|
580
|
+
uniqueIdProperty,
|
|
581
|
+
options
|
|
582
|
+
});
|
|
517
583
|
}
|
|
584
|
+
return Array.from(map.values());
|
|
518
585
|
}
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
const DEFAULT_REQUEST_CACHE = new Map();
|
|
531
|
-
async function requestWithParameters({
|
|
532
|
-
baseUrl,
|
|
533
|
-
parameters = {},
|
|
534
|
-
headers: customHeaders = {},
|
|
535
|
-
errorContext,
|
|
536
|
-
maxLengthURL = DEFAULT_MAX_LENGTH_URL,
|
|
537
|
-
localCache
|
|
586
|
+
function processTileFeatureProperties({
|
|
587
|
+
map,
|
|
588
|
+
data,
|
|
589
|
+
startIndex,
|
|
590
|
+
endIndex,
|
|
591
|
+
type,
|
|
592
|
+
bbox,
|
|
593
|
+
tileFormat,
|
|
594
|
+
uniqueIdProperty,
|
|
595
|
+
storeGeometry,
|
|
596
|
+
geometryIntersection
|
|
538
597
|
}) {
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
v: V3_MINOR_VERSION,
|
|
544
|
-
client: getClient()
|
|
545
|
-
}, typeof deck !== 'undefined' && deck.VERSION && {
|
|
546
|
-
deckglVersion: deck.VERSION
|
|
547
|
-
}, parameters);
|
|
548
|
-
baseUrl = excludeURLParameters(baseUrl, Object.keys(parameters));
|
|
549
|
-
const key = createCacheKey(baseUrl, parameters, customHeaders);
|
|
550
|
-
const {
|
|
551
|
-
cache: REQUEST_CACHE,
|
|
552
|
-
canReadCache,
|
|
553
|
-
canStoreInCache
|
|
554
|
-
} = getCacheSettings(localCache);
|
|
555
|
-
if (canReadCache && REQUEST_CACHE.has(key)) {
|
|
556
|
-
return REQUEST_CACHE.get(key);
|
|
598
|
+
const tileProps = getPropertiesFromTile(data, startIndex);
|
|
599
|
+
const uniquePropertyValue = getUniquePropertyValue(tileProps, uniqueIdProperty, map);
|
|
600
|
+
if (!uniquePropertyValue || map.has(uniquePropertyValue)) {
|
|
601
|
+
return;
|
|
557
602
|
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
headers
|
|
567
|
-
});
|
|
568
|
-
let response;
|
|
569
|
-
let responseJson;
|
|
570
|
-
const jsonPromise = fetchPromise.then(_response => {
|
|
571
|
-
response = _response;
|
|
572
|
-
return response.json();
|
|
573
|
-
}).then(json => {
|
|
574
|
-
responseJson = json;
|
|
575
|
-
if (!response || !response.ok) {
|
|
576
|
-
throw new Error(json.error);
|
|
577
|
-
}
|
|
578
|
-
return json;
|
|
579
|
-
}).catch(error => {
|
|
580
|
-
if (canStoreInCache) {
|
|
581
|
-
REQUEST_CACHE.delete(key);
|
|
582
|
-
}
|
|
583
|
-
throw new CartoAPIError(error, errorContext, response, responseJson);
|
|
584
|
-
});
|
|
585
|
-
if (canStoreInCache) {
|
|
586
|
-
REQUEST_CACHE.set(key, jsonPromise);
|
|
603
|
+
let geometry = null;
|
|
604
|
+
// Only calculate geometry if necessary
|
|
605
|
+
if (storeGeometry || geometryIntersection) {
|
|
606
|
+
const {
|
|
607
|
+
positions
|
|
608
|
+
} = data;
|
|
609
|
+
const ringCoordinates = getRingCoordinatesFor(startIndex, endIndex, positions);
|
|
610
|
+
geometry = getFeatureByType(ringCoordinates, type);
|
|
587
611
|
}
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
const
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
canStoreInCache
|
|
599
|
-
};
|
|
612
|
+
// If intersection is required, check before proceeding
|
|
613
|
+
if (geometry && geometryIntersection && !intersects(geometry, geometryIntersection)) {
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
const properties = parseProperties(tileProps);
|
|
617
|
+
// Only save geometry if necessary
|
|
618
|
+
if (storeGeometry && geometry) {
|
|
619
|
+
properties[FEATURE_GEOM_PROPERTY] = tileFormat === TileFormat.MVT ? transformTileCoordsToWGS84(geometry, bbox) : geometry;
|
|
620
|
+
}
|
|
621
|
+
map.set(uniquePropertyValue, properties);
|
|
600
622
|
}
|
|
601
|
-
function
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
623
|
+
function addIntersectedFeaturesInTile({
|
|
624
|
+
map,
|
|
625
|
+
data,
|
|
626
|
+
geometryIntersection,
|
|
627
|
+
type,
|
|
628
|
+
bbox,
|
|
629
|
+
tileFormat,
|
|
630
|
+
uniqueIdProperty,
|
|
631
|
+
options
|
|
632
|
+
}) {
|
|
633
|
+
const indices = getIndices(data);
|
|
634
|
+
const storeGeometry = (options == null ? void 0 : options.storeGeometry) || false;
|
|
635
|
+
for (let i = 0; i < indices.length - 1; i++) {
|
|
636
|
+
const startIndex = indices[i];
|
|
637
|
+
const endIndex = indices[i + 1];
|
|
638
|
+
processTileFeatureProperties({
|
|
639
|
+
map,
|
|
640
|
+
data,
|
|
641
|
+
startIndex,
|
|
642
|
+
endIndex,
|
|
643
|
+
type,
|
|
644
|
+
bbox,
|
|
645
|
+
tileFormat,
|
|
646
|
+
uniqueIdProperty,
|
|
647
|
+
storeGeometry,
|
|
648
|
+
geometryIntersection
|
|
649
|
+
});
|
|
650
|
+
}
|
|
609
651
|
}
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
652
|
+
function getIndices(data) {
|
|
653
|
+
let indices;
|
|
654
|
+
switch (data.type) {
|
|
655
|
+
case 'Point':
|
|
656
|
+
// @ts-expect-error Missing or changed types?
|
|
657
|
+
indices = data.pointIndices;
|
|
658
|
+
break;
|
|
659
|
+
case 'LineString':
|
|
660
|
+
indices = data.pathIndices;
|
|
661
|
+
break;
|
|
662
|
+
case 'Polygon':
|
|
663
|
+
indices = data.primitivePolygonIndices;
|
|
664
|
+
break;
|
|
665
|
+
default:
|
|
666
|
+
throw new Error(`Unexpected type, "${data.type}"`);
|
|
623
667
|
}
|
|
624
|
-
return
|
|
668
|
+
return indices.value;
|
|
625
669
|
}
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
function
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
670
|
+
function getFeatureId(data, startIndex) {
|
|
671
|
+
return data.featureIds.value[startIndex];
|
|
672
|
+
}
|
|
673
|
+
function getPropertiesFromTile(data, startIndex) {
|
|
674
|
+
var _fields$featureId;
|
|
675
|
+
const featureId = getFeatureId(data, startIndex);
|
|
676
|
+
const {
|
|
677
|
+
properties,
|
|
678
|
+
numericProps,
|
|
679
|
+
fields
|
|
680
|
+
} = data;
|
|
681
|
+
const result = {
|
|
682
|
+
uniqueId: fields == null || (_fields$featureId = fields[featureId]) == null ? void 0 : _fields$featureId.id,
|
|
683
|
+
properties: properties[featureId],
|
|
684
|
+
numericProps: {}
|
|
685
|
+
};
|
|
686
|
+
for (const key in numericProps) {
|
|
687
|
+
result.numericProps[key] = numericProps[key].value[startIndex];
|
|
635
688
|
}
|
|
636
|
-
return
|
|
689
|
+
return result;
|
|
637
690
|
}
|
|
638
|
-
|
|
639
|
-
const _excluded$3 = ["accessToken", "connectionName", "cache"];
|
|
640
|
-
const SOURCE_DEFAULTS = {
|
|
641
|
-
apiBaseUrl: DEFAULT_API_BASE_URL,
|
|
642
|
-
clientId: getClient(),
|
|
643
|
-
format: 'tilejson',
|
|
644
|
-
headers: {},
|
|
645
|
-
maxLengthURL: DEFAULT_MAX_LENGTH_URL
|
|
646
|
-
};
|
|
647
|
-
async function baseSource(endpoint, options, urlParameters) {
|
|
691
|
+
function parseProperties(tileProps) {
|
|
648
692
|
const {
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
endpoint
|
|
658
|
-
});
|
|
659
|
-
for (const key in optionalOptions) {
|
|
660
|
-
if (optionalOptions[key]) {
|
|
661
|
-
mergedOptions[key] = optionalOptions[key];
|
|
662
|
-
}
|
|
693
|
+
properties,
|
|
694
|
+
numericProps
|
|
695
|
+
} = tileProps;
|
|
696
|
+
return Object.assign({}, properties, numericProps);
|
|
697
|
+
}
|
|
698
|
+
function getUniquePropertyValue(tileProps, uniqueIdProperty, map) {
|
|
699
|
+
if (uniqueIdProperty) {
|
|
700
|
+
return getValueFromTileProps(tileProps, uniqueIdProperty);
|
|
663
701
|
}
|
|
664
|
-
|
|
702
|
+
if (tileProps.uniqueId) {
|
|
703
|
+
return tileProps.uniqueId;
|
|
704
|
+
}
|
|
705
|
+
const artificialId = map.size + 1; // a counter, assumed as a valid new id
|
|
706
|
+
return getValueFromTileProps(tileProps, 'cartodb_id') || getValueFromTileProps(tileProps, 'geoid') || artificialId;
|
|
707
|
+
}
|
|
708
|
+
function getValueFromTileProps(tileProps, propertyName) {
|
|
665
709
|
const {
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
});
|
|
691
|
-
const dataUrl = mapInstantiation[format].url[0];
|
|
692
|
-
if (cache) {
|
|
693
|
-
cache.value = parseInt(new URL(dataUrl).searchParams.get('cache') || '', 10);
|
|
710
|
+
properties,
|
|
711
|
+
numericProps
|
|
712
|
+
} = tileProps;
|
|
713
|
+
return numericProps[propertyName] || properties[propertyName];
|
|
714
|
+
}
|
|
715
|
+
function getFeatureByType(coordinates, type) {
|
|
716
|
+
switch (type) {
|
|
717
|
+
case 'Polygon':
|
|
718
|
+
return {
|
|
719
|
+
type: 'Polygon',
|
|
720
|
+
coordinates: [coordinates]
|
|
721
|
+
};
|
|
722
|
+
case 'LineString':
|
|
723
|
+
return {
|
|
724
|
+
type: 'LineString',
|
|
725
|
+
coordinates
|
|
726
|
+
};
|
|
727
|
+
case 'Point':
|
|
728
|
+
return {
|
|
729
|
+
type: 'Point',
|
|
730
|
+
coordinates: coordinates[0]
|
|
731
|
+
};
|
|
732
|
+
default:
|
|
733
|
+
throw new Error('Invalid geometry type');
|
|
694
734
|
}
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
errorContext,
|
|
701
|
-
maxLengthURL,
|
|
702
|
-
localCache
|
|
703
|
-
});
|
|
704
|
-
if (accessToken) {
|
|
705
|
-
json.accessToken = accessToken;
|
|
706
|
-
}
|
|
707
|
-
return json;
|
|
735
|
+
}
|
|
736
|
+
function getRingCoordinatesFor(startIndex, endIndex, positions) {
|
|
737
|
+
const ringCoordinates = [];
|
|
738
|
+
for (let j = startIndex; j < endIndex; j++) {
|
|
739
|
+
ringCoordinates.push(Array.from(positions.value.subarray(j * positions.size, (j + 1) * positions.size)));
|
|
708
740
|
}
|
|
709
|
-
return
|
|
710
|
-
baseUrl: dataUrl,
|
|
711
|
-
headers,
|
|
712
|
-
errorContext,
|
|
713
|
-
maxLengthURL,
|
|
714
|
-
localCache
|
|
715
|
-
});
|
|
741
|
+
return ringCoordinates;
|
|
716
742
|
}
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
tilesetTableName,
|
|
731
|
-
propertiesSqlQuery
|
|
732
|
-
};
|
|
733
|
-
if (columns) {
|
|
734
|
-
urlParameters.columns = columns.join(',');
|
|
743
|
+
function calculateFeatures({
|
|
744
|
+
map,
|
|
745
|
+
tileIsFullyVisible,
|
|
746
|
+
geometryIntersection,
|
|
747
|
+
data,
|
|
748
|
+
type,
|
|
749
|
+
bbox,
|
|
750
|
+
tileFormat,
|
|
751
|
+
uniqueIdProperty,
|
|
752
|
+
options
|
|
753
|
+
}) {
|
|
754
|
+
if (!(data != null && data.properties.length)) {
|
|
755
|
+
return;
|
|
735
756
|
}
|
|
736
|
-
if (
|
|
737
|
-
|
|
757
|
+
if (tileIsFullyVisible) {
|
|
758
|
+
addAllFeaturesInTile({
|
|
759
|
+
map,
|
|
760
|
+
data,
|
|
761
|
+
type,
|
|
762
|
+
bbox,
|
|
763
|
+
tileFormat,
|
|
764
|
+
uniqueIdProperty,
|
|
765
|
+
options
|
|
766
|
+
});
|
|
767
|
+
} else {
|
|
768
|
+
addIntersectedFeaturesInTile({
|
|
769
|
+
map,
|
|
770
|
+
data,
|
|
771
|
+
geometryIntersection,
|
|
772
|
+
type,
|
|
773
|
+
bbox,
|
|
774
|
+
tileFormat,
|
|
775
|
+
uniqueIdProperty,
|
|
776
|
+
options
|
|
777
|
+
});
|
|
738
778
|
}
|
|
739
|
-
|
|
740
|
-
|
|
779
|
+
}
|
|
780
|
+
function addAllFeaturesInTile({
|
|
781
|
+
map,
|
|
782
|
+
data,
|
|
783
|
+
type,
|
|
784
|
+
bbox,
|
|
785
|
+
tileFormat,
|
|
786
|
+
uniqueIdProperty,
|
|
787
|
+
options
|
|
788
|
+
}) {
|
|
789
|
+
const indices = getIndices(data);
|
|
790
|
+
const storeGeometry = (options == null ? void 0 : options.storeGeometry) || false;
|
|
791
|
+
for (let i = 0; i < indices.length - 1; i++) {
|
|
792
|
+
const startIndex = indices[i];
|
|
793
|
+
const endIndex = indices[i + 1];
|
|
794
|
+
processTileFeatureProperties({
|
|
795
|
+
map,
|
|
796
|
+
data,
|
|
797
|
+
startIndex,
|
|
798
|
+
endIndex,
|
|
799
|
+
type,
|
|
800
|
+
bbox,
|
|
801
|
+
tileFormat,
|
|
802
|
+
uniqueIdProperty,
|
|
803
|
+
storeGeometry
|
|
804
|
+
});
|
|
741
805
|
}
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
filters,
|
|
751
|
-
tilesetTableName,
|
|
752
|
-
columns,
|
|
753
|
-
propertiesTableName
|
|
754
|
-
} = options;
|
|
755
|
-
const urlParameters = {
|
|
756
|
-
tilesetTableName,
|
|
757
|
-
propertiesTableName
|
|
806
|
+
}
|
|
807
|
+
function createIndicesForPoints(data) {
|
|
808
|
+
const featureIds = data.featureIds.value;
|
|
809
|
+
const lastFeatureId = featureIds[featureIds.length - 1];
|
|
810
|
+
const PointIndicesArray = featureIds.constructor;
|
|
811
|
+
const pointIndices = {
|
|
812
|
+
value: new PointIndicesArray(featureIds.length + 1),
|
|
813
|
+
size: 1
|
|
758
814
|
};
|
|
759
|
-
|
|
760
|
-
|
|
815
|
+
pointIndices.value.set(featureIds);
|
|
816
|
+
pointIndices.value.set([lastFeatureId + 1], featureIds.length);
|
|
817
|
+
// @ts-expect-error Missing or changed types?
|
|
818
|
+
data.pointIndices = pointIndices;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
function tileFeaturesSpatialIndex({
|
|
822
|
+
tiles,
|
|
823
|
+
spatialFilter,
|
|
824
|
+
spatialDataColumn,
|
|
825
|
+
spatialDataType
|
|
826
|
+
}) {
|
|
827
|
+
const map = new Map();
|
|
828
|
+
const spatialIndex = getSpatialIndex(spatialDataType);
|
|
829
|
+
const resolution = getResolution(tiles, spatialIndex);
|
|
830
|
+
const spatialIndexIDName = spatialDataColumn ? spatialDataColumn : spatialIndex;
|
|
831
|
+
if (!resolution) {
|
|
832
|
+
return [];
|
|
761
833
|
}
|
|
762
|
-
|
|
763
|
-
|
|
834
|
+
const cells = getCellsCoverGeometry(spatialFilter, spatialIndex, resolution);
|
|
835
|
+
if (!(cells != null && cells.length)) {
|
|
836
|
+
return [];
|
|
764
837
|
}
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
const tileSize = DEFAULT_TILE_SIZE;
|
|
779
|
-
const maxResolutionForZoom = (_maxH3SpatialFiltersR = (_maxH3SpatialFiltersR2 = maxH3SpatialFiltersResolutions.find(([zoom]) => zoom === currentZoomInt)) == null ? void 0 : _maxH3SpatialFiltersR2[1]) != null ? _maxH3SpatialFiltersR : Math.max(0, currentZoomInt - 3);
|
|
780
|
-
const maxSpatialFiltersResolution = maxResolutionForZoom ? Math.min(dataResolution, maxResolutionForZoom) : dataResolution;
|
|
781
|
-
const hexagonResolution = _getHexagonResolution(viewState, tileSize) + aggregationResLevelOffset;
|
|
782
|
-
return Math.min(hexagonResolution, maxSpatialFiltersResolution);
|
|
838
|
+
// We transform cells to Set to improve the performace
|
|
839
|
+
const cellsSet = new Set(cells);
|
|
840
|
+
for (const tile of tiles) {
|
|
841
|
+
if (tile.isVisible === false || !tile.data) {
|
|
842
|
+
continue;
|
|
843
|
+
}
|
|
844
|
+
tile.data.forEach(d => {
|
|
845
|
+
if (cellsSet.has(d.id)) {
|
|
846
|
+
map.set(d.id, _extends({}, d.properties, {
|
|
847
|
+
[spatialIndexIDName]: d.id
|
|
848
|
+
}));
|
|
849
|
+
}
|
|
850
|
+
});
|
|
783
851
|
}
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
852
|
+
return Array.from(map.values());
|
|
853
|
+
}
|
|
854
|
+
function getResolution(tiles, spatialIndex) {
|
|
855
|
+
var _tiles$find;
|
|
856
|
+
const data = (_tiles$find = tiles.find(tile => {
|
|
857
|
+
var _tile$data;
|
|
858
|
+
return (_tile$data = tile.data) == null ? void 0 : _tile$data.length;
|
|
859
|
+
})) == null ? void 0 : _tiles$find.data;
|
|
860
|
+
if (!data) {
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
if (spatialIndex === SpatialIndex.QUADBIN) {
|
|
864
|
+
return Number(getResolution$1(data[0].id));
|
|
865
|
+
}
|
|
866
|
+
if (spatialIndex === SpatialIndex.H3) {
|
|
867
|
+
return getResolution$2(data[0].id);
|
|
789
868
|
}
|
|
790
|
-
return undefined;
|
|
791
869
|
}
|
|
792
|
-
const
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
870
|
+
const bboxWest = [-180, -90, 0, 90];
|
|
871
|
+
const bboxEast = [0, -90, 180, 90];
|
|
872
|
+
function getCellsCoverGeometry(geometry, spatialIndex, resolution) {
|
|
873
|
+
if (spatialIndex === SpatialIndex.QUADBIN) {
|
|
874
|
+
// @ts-expect-error TODO: Probably ought to be stricter about number vs. bigint types in this file.
|
|
875
|
+
return geometryToCells(geometry, resolution);
|
|
876
|
+
}
|
|
877
|
+
if (spatialIndex === SpatialIndex.H3) {
|
|
878
|
+
// The current H3 polyfill algorithm can't deal with polygon segments of greater than 180 degrees longitude
|
|
879
|
+
// so we clip the geometry to be sure that none of them is greater than 180 degrees
|
|
880
|
+
// https://github.com/uber/h3-js/issues/24#issuecomment-431893796
|
|
881
|
+
return polygonToCells(bboxClip(geometry, bboxWest).geometry.coordinates, resolution, true).concat(polygonToCells(bboxClip(geometry, bboxEast).geometry.coordinates, resolution, true));
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
function getSpatialIndex(spatialDataType) {
|
|
885
|
+
switch (spatialDataType) {
|
|
886
|
+
case 'h3':
|
|
887
|
+
return SpatialIndex.H3;
|
|
888
|
+
case 'quadbin':
|
|
889
|
+
return SpatialIndex.QUADBIN;
|
|
890
|
+
default:
|
|
891
|
+
throw new Error('Unexpected spatial data type');
|
|
892
|
+
}
|
|
810
893
|
}
|
|
811
894
|
|
|
812
895
|
/**
|
|
813
|
-
*
|
|
814
|
-
*
|
|
815
|
-
* Abstract class. Use {@link WidgetQuerySource} or {@link WidgetTableSource}.
|
|
896
|
+
* Current version of @carto/api-client.
|
|
897
|
+
* @internal
|
|
816
898
|
*/
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
899
|
+
/** @internal */
|
|
900
|
+
const V3_MINOR_VERSION = '3.4';
|
|
901
|
+
/** @privateRemarks Source: @carto/constants, @deck.gl/carto */
|
|
902
|
+
const DEFAULT_GEO_COLUMN = 'geom';
|
|
903
|
+
/**
|
|
904
|
+
* Fastly default limit is 8192; leave some padding.
|
|
905
|
+
* @privateRemarks Source: @deck.gl/carto
|
|
906
|
+
*/
|
|
907
|
+
const DEFAULT_MAX_LENGTH_URL = 7000;
|
|
908
|
+
/** @privateRemarks Source: @deck.gl/carto */
|
|
909
|
+
const DEFAULT_TILE_RESOLUTION = 0.5;
|
|
910
|
+
/**
|
|
911
|
+
* @privateRemarks Source: @deck.gl/carto
|
|
912
|
+
* @internal
|
|
913
|
+
*/
|
|
914
|
+
const DEFAULT_AGGREGATION_RES_LEVEL_H3 = 4;
|
|
915
|
+
/**
|
|
916
|
+
* @privateRemarks Source: @deck.gl/carto
|
|
917
|
+
* @internal
|
|
918
|
+
*/
|
|
919
|
+
const DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN = 6;
|
|
920
|
+
|
|
921
|
+
const _excluded$2 = ["tiles"];
|
|
922
|
+
function tileFeaturesRaster(_ref) {
|
|
923
|
+
let {
|
|
924
|
+
tiles
|
|
925
|
+
} = _ref,
|
|
926
|
+
options = _objectWithoutPropertiesLoose(_ref, _excluded$2);
|
|
927
|
+
// Cache band metadata for faster lookup while iterating over pixels.
|
|
928
|
+
const bandMetadataByName = {};
|
|
929
|
+
for (const band of options.rasterMetadata.bands) {
|
|
930
|
+
bandMetadataByName[band.name] = band;
|
|
836
931
|
}
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
932
|
+
// Omit empty and invisible tiles for simpler processing and types.
|
|
933
|
+
tiles = tiles.filter(isRasterTileVisible);
|
|
934
|
+
if (tiles.length === 0) return [];
|
|
935
|
+
// Raster tiles, and all pixels, are quadbin cells. Resolution of a pixel is
|
|
936
|
+
// the resolution of the tile, plus the number of subdivisions. Block size
|
|
937
|
+
// must be square, N x N, where N is a power of two.
|
|
938
|
+
const tileResolution = getResolution$1(tiles[0].index.q);
|
|
939
|
+
const tileBlockSize = tiles[0].data.blockSize;
|
|
940
|
+
const cellResolution = tileResolution + BigInt(Math.log2(tileBlockSize));
|
|
941
|
+
// Compute covering cells for the spatial filter, at same resolution as the
|
|
942
|
+
// raster pixels, to be used as a mask.
|
|
943
|
+
const spatialFilterCells = new Set(geometryToCells(options.spatialFilter, cellResolution));
|
|
944
|
+
const data = new Map();
|
|
945
|
+
for (const tile of tiles) {
|
|
946
|
+
const parent = tile.index.q;
|
|
947
|
+
const children = cellToChildrenSorted(parent, cellResolution);
|
|
948
|
+
// For each pixel/cell within the spatial filter, create a FeatureData.
|
|
949
|
+
// Order is row-major, starting from NW and ending at SE.
|
|
950
|
+
for (let i = 0; i < children.length; i++) {
|
|
951
|
+
if (!spatialFilterCells.has(children[i])) continue;
|
|
952
|
+
const cellData = {};
|
|
953
|
+
let cellDataExists = false;
|
|
954
|
+
for (const band in tile.data.cells.numericProps) {
|
|
955
|
+
const value = tile.data.cells.numericProps[band].value[i];
|
|
956
|
+
// TODO(cleanup): nodata should be a number, not a string.
|
|
957
|
+
if (Number(bandMetadataByName[band].nodata) !== value) {
|
|
958
|
+
cellData[band] = tile.data.cells.numericProps[band].value[i];
|
|
959
|
+
cellDataExists = true;
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
if (cellDataExists) {
|
|
963
|
+
data.set(children[i], cellData);
|
|
964
|
+
}
|
|
844
965
|
}
|
|
845
|
-
return getSpatialFiltersResolution(source, referenceViewState);
|
|
846
966
|
}
|
|
967
|
+
return Array.from(data.values());
|
|
968
|
+
}
|
|
969
|
+
/**
|
|
970
|
+
* Detects whether a given {@link Tile} is a {@link RasterTile}.
|
|
971
|
+
* @privateRemarks Method of detection is arbitrary, and may be changed.
|
|
972
|
+
*/
|
|
973
|
+
function isRasterTile(tile) {
|
|
974
|
+
var _tile$data;
|
|
975
|
+
return !!((_tile$data = tile.data) != null && _tile$data.cells);
|
|
976
|
+
}
|
|
977
|
+
function isRasterTileVisible(tile) {
|
|
978
|
+
var _tile$data2;
|
|
979
|
+
return !!(tile.isVisible && (_tile$data2 = tile.data) != null && (_tile$data2 = _tile$data2.cells) != null && _tile$data2.numericProps);
|
|
980
|
+
}
|
|
981
|
+
/**
|
|
982
|
+
* For the raster format, children are sorted in row-major order, starting from
|
|
983
|
+
* NW and ending at SE. Order returned by quadbin's cellToChildren() is not
|
|
984
|
+
* defined (and not related to the raster format), so sort explicitly here.
|
|
985
|
+
*/
|
|
986
|
+
function cellToChildrenSorted(parent, resolution) {
|
|
987
|
+
return cellToChildren(parent, resolution).sort((cellA, cellB) => {
|
|
988
|
+
const tileA = cellToTile(cellA);
|
|
989
|
+
const tileB = cellToTile(cellB);
|
|
990
|
+
if (tileA.y !== tileB.y) {
|
|
991
|
+
return tileA.y > tileB.y ? 1 : -1;
|
|
992
|
+
}
|
|
993
|
+
return tileA.x > tileB.x ? 1 : -1;
|
|
994
|
+
});
|
|
847
995
|
}
|
|
848
|
-
WidgetSource.defaultProps = {
|
|
849
|
-
apiVersion: ApiVersion.V3,
|
|
850
|
-
apiBaseUrl: DEFAULT_API_BASE_URL,
|
|
851
|
-
clientId: getClient(),
|
|
852
|
-
filters: {},
|
|
853
|
-
filtersLogicalOperator: 'and'
|
|
854
|
-
};
|
|
855
996
|
|
|
997
|
+
const FILTER_TYPES = new Set(Object.values(FilterType));
|
|
998
|
+
const isFilterType = type => FILTER_TYPES.has(type);
|
|
856
999
|
/**
|
|
857
|
-
*
|
|
858
|
-
* @
|
|
1000
|
+
* @privateRemarks Source: @carto/react-widgets
|
|
1001
|
+
* @internal
|
|
859
1002
|
*/
|
|
860
|
-
function
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
throw new Error('Unauthorized access. Invalid credentials');
|
|
874
|
-
case 403:
|
|
875
|
-
throw new Error('Forbidden access to the requested data');
|
|
876
|
-
default:
|
|
877
|
-
const msg = data && data.error && typeof data.error === 'string' ? data.error : JSON.stringify((data == null ? void 0 : data.hint) || ((_data$error2 = data.error) == null ? void 0 : _data$error2[0]));
|
|
878
|
-
throw new Error(msg);
|
|
1003
|
+
function getApplicableFilters(owner, filters) {
|
|
1004
|
+
if (!filters) return {};
|
|
1005
|
+
const applicableFilters = {};
|
|
1006
|
+
for (const column in filters) {
|
|
1007
|
+
for (const type in filters[column]) {
|
|
1008
|
+
if (!isFilterType(type)) continue;
|
|
1009
|
+
const filter = filters[column][type];
|
|
1010
|
+
const isApplicable = !owner || !(filter != null && filter.owner) || (filter == null ? void 0 : filter.owner) !== owner;
|
|
1011
|
+
if (filter && isApplicable) {
|
|
1012
|
+
applicableFilters[column] || (applicableFilters[column] = {});
|
|
1013
|
+
applicableFilters[column][type] = filter;
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
879
1016
|
}
|
|
1017
|
+
return applicableFilters;
|
|
880
1018
|
}
|
|
881
|
-
/**
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
headers: _extends({
|
|
894
|
-
Authorization: `Bearer ${accessToken}`
|
|
895
|
-
}, isPost && {
|
|
896
|
-
'Content-Type': 'application/json'
|
|
897
|
-
})
|
|
898
|
-
}, isPost && {
|
|
899
|
-
method: opts == null ? void 0 : opts.method,
|
|
900
|
-
body: opts == null ? void 0 : opts.body
|
|
901
|
-
}, {
|
|
902
|
-
signal: opts == null || (_opts$abortController = opts.abortController) == null ? void 0 : _opts$abortController.signal
|
|
903
|
-
}, opts == null ? void 0 : opts.otherOptions));
|
|
904
|
-
data = await response.json();
|
|
905
|
-
} catch (error) {
|
|
906
|
-
if (error.name === 'AbortError') throw error;
|
|
907
|
-
throw new Error(`Failed request: ${error}`);
|
|
1019
|
+
/**
|
|
1020
|
+
* Due to each data warehouse having its own behavior with columns,
|
|
1021
|
+
* we need to normalize them and transform every key to lowercase.
|
|
1022
|
+
*
|
|
1023
|
+
* @privateRemarks Source: @carto/react-widgets
|
|
1024
|
+
* @internal
|
|
1025
|
+
*/
|
|
1026
|
+
function normalizeObjectKeys(el) {
|
|
1027
|
+
if (Array.isArray(el)) {
|
|
1028
|
+
return el.map(value => normalizeObjectKeys(value));
|
|
1029
|
+
} else if (typeof el !== 'object') {
|
|
1030
|
+
return el;
|
|
908
1031
|
}
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
1032
|
+
return Object.entries(el).reduce((acc, [key, value]) => {
|
|
1033
|
+
acc[key.toLowerCase()] = typeof value === 'object' && value ? normalizeObjectKeys(value) : value;
|
|
1034
|
+
return acc;
|
|
1035
|
+
}, {});
|
|
1036
|
+
}
|
|
1037
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
1038
|
+
function assert(condition, message) {
|
|
1039
|
+
if (!condition) {
|
|
1040
|
+
throw new Error(message);
|
|
914
1041
|
}
|
|
915
|
-
return data;
|
|
916
1042
|
}
|
|
917
|
-
|
|
918
|
-
/** @internalRemarks Source: @carto/react-api */
|
|
919
|
-
const AVAILABLE_MODELS = ['category', 'histogram', 'formula', 'pick', 'timeseries', 'range', 'scatterplot', 'table'];
|
|
920
|
-
const {
|
|
921
|
-
V3
|
|
922
|
-
} = ApiVersion;
|
|
923
|
-
const REQUEST_GET_MAX_URL_LENGTH = 2048;
|
|
924
1043
|
/**
|
|
925
|
-
*
|
|
926
|
-
* @
|
|
1044
|
+
* @privateRemarks Source: @carto/react-core
|
|
1045
|
+
* @internal
|
|
927
1046
|
*/
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
1047
|
+
class InvalidColumnError extends Error {
|
|
1048
|
+
constructor(message) {
|
|
1049
|
+
super(`${InvalidColumnError.NAME}: ${message}`);
|
|
1050
|
+
this.name = InvalidColumnError.NAME;
|
|
1051
|
+
}
|
|
1052
|
+
static is(error) {
|
|
1053
|
+
var _error$message;
|
|
1054
|
+
return error instanceof InvalidColumnError || ((_error$message = error.message) == null ? void 0 : _error$message.includes(InvalidColumnError.NAME));
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
InvalidColumnError.NAME = 'InvalidColumnError';
|
|
1058
|
+
function isEmptyObject(object) {
|
|
1059
|
+
for (const _ in object) {
|
|
1060
|
+
return false;
|
|
1061
|
+
}
|
|
1062
|
+
return true;
|
|
1063
|
+
}
|
|
1064
|
+
/** @internal */
|
|
1065
|
+
const isObject = x => x !== null && typeof x === 'object';
|
|
1066
|
+
/** @internal */
|
|
1067
|
+
const isPureObject = x => isObject(x) && x.constructor === {}.constructor;
|
|
1068
|
+
|
|
1069
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
1070
|
+
function tileFeatures({
|
|
1071
|
+
tiles,
|
|
1072
|
+
spatialFilter,
|
|
1073
|
+
uniqueIdProperty,
|
|
1074
|
+
tileFormat,
|
|
1075
|
+
spatialDataColumn = DEFAULT_GEO_COLUMN,
|
|
1076
|
+
spatialDataType,
|
|
1077
|
+
rasterMetadata,
|
|
1078
|
+
options = {}
|
|
1079
|
+
}) {
|
|
1080
|
+
if (spatialDataType === 'geo') {
|
|
1081
|
+
return tileFeaturesGeometries({
|
|
1082
|
+
tiles,
|
|
1083
|
+
tileFormat,
|
|
1084
|
+
spatialFilter,
|
|
1085
|
+
uniqueIdProperty,
|
|
1086
|
+
options
|
|
1087
|
+
});
|
|
1088
|
+
}
|
|
1089
|
+
if (tiles.some(isRasterTile)) {
|
|
1090
|
+
assert(rasterMetadata, 'Missing raster metadata');
|
|
1091
|
+
return tileFeaturesRaster({
|
|
1092
|
+
tiles: tiles,
|
|
1093
|
+
spatialFilter,
|
|
1094
|
+
spatialDataColumn,
|
|
1095
|
+
spatialDataType,
|
|
1096
|
+
rasterMetadata
|
|
1097
|
+
});
|
|
1098
|
+
}
|
|
1099
|
+
return tileFeaturesSpatialIndex({
|
|
1100
|
+
tiles: tiles,
|
|
1101
|
+
spatialFilter,
|
|
1102
|
+
spatialDataColumn,
|
|
1103
|
+
spatialDataType
|
|
1104
|
+
});
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
/**
|
|
1108
|
+
* Creates props for DataFilterExtension, from `@deck.gl/extensions`, given
|
|
1109
|
+
* a set of filters.
|
|
1110
|
+
*
|
|
1111
|
+
* @privateRemarks DataFilterExtension accepts up to 4 values to filter. This
|
|
1112
|
+
* implementation uses the 1st for all filters except the time filter, and the
|
|
1113
|
+
* 2nd for the time filter.
|
|
1114
|
+
*/
|
|
1115
|
+
function getDataFilterExtensionProps(filters, filtersLogicalOperator, filterSize) {
|
|
1116
|
+
var _filterSize;
|
|
1117
|
+
(_filterSize = filterSize) != null ? _filterSize : filterSize = 4;
|
|
952
1118
|
const {
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
1119
|
+
filtersWithoutTimeType,
|
|
1120
|
+
timeColumn,
|
|
1121
|
+
timeFilter
|
|
1122
|
+
} = getFiltersByType(filters);
|
|
1123
|
+
return {
|
|
1124
|
+
filterRange: getFilterRange(timeFilter, filterSize),
|
|
1125
|
+
updateTriggers: getUpdateTriggers(filtersWithoutTimeType, timeColumn, timeFilter),
|
|
1126
|
+
getFilterValue: getFilterValue(filtersWithoutTimeType, timeColumn, timeFilter, filterSize, filtersLogicalOperator)
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1129
|
+
/** @internal */
|
|
1130
|
+
function getFiltersByType(filters) {
|
|
1131
|
+
const filtersWithoutTimeType = {};
|
|
1132
|
+
let timeColumn = null;
|
|
1133
|
+
let timeFilter = null;
|
|
1134
|
+
for (const [column, columnData] of Object.entries(filters)) {
|
|
1135
|
+
for (const [type, typeData] of Object.entries(columnData)) {
|
|
1136
|
+
if (type === FilterType.TIME) {
|
|
1137
|
+
timeColumn = column;
|
|
1138
|
+
timeFilter = typeData;
|
|
1139
|
+
} else {
|
|
1140
|
+
filtersWithoutTimeType[column] = {
|
|
1141
|
+
[type]: typeData
|
|
1142
|
+
};
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
return {
|
|
1147
|
+
filtersWithoutTimeType,
|
|
1148
|
+
timeColumn,
|
|
1149
|
+
timeFilter
|
|
1150
|
+
};
|
|
1151
|
+
}
|
|
1152
|
+
/** @internal */
|
|
1153
|
+
function getFilterRange(timeFilter, filterSize) {
|
|
1154
|
+
const result = Array(filterSize).fill([0, 0]);
|
|
1155
|
+
// According to getFilterValue all filters are resolved as 0 or 1 in the first position of the array
|
|
1156
|
+
// except the time filter value that is resolved with the real value of the feature in the second position of the array
|
|
1157
|
+
result[0] = [1, 1];
|
|
1158
|
+
if (timeFilter) {
|
|
1159
|
+
var _timeFilter$params;
|
|
1160
|
+
const offsetBy = ((_timeFilter$params = timeFilter.params) == null ? void 0 : _timeFilter$params.offsetBy) || 0;
|
|
1161
|
+
result[1] = timeFilter.values[0].map(v => v - offsetBy);
|
|
1162
|
+
}
|
|
1163
|
+
return result;
|
|
1164
|
+
}
|
|
1165
|
+
/** @internal */
|
|
1166
|
+
function getUpdateTriggers(filtersWithoutTimeType, timeColumn, timeFilter) {
|
|
1167
|
+
const result = _extends({}, filtersWithoutTimeType);
|
|
1168
|
+
// We don't want to change the layer UpdateTriggers every time that the time filter changes
|
|
1169
|
+
// because this filter is changed by the time series widget during its animation
|
|
1170
|
+
// so we remove the time filter value from the `updateTriggers`
|
|
1171
|
+
if (timeColumn && timeFilter) {
|
|
1172
|
+
var _timeFilter$params2;
|
|
1173
|
+
result[timeColumn] = _extends({}, result[timeColumn], {
|
|
1174
|
+
offsetBy: (_timeFilter$params2 = timeFilter.params) == null ? void 0 : _timeFilter$params2.offsetBy,
|
|
1175
|
+
[FilterType.TIME]: {} // Allows working with other filters, without an impact on performance.
|
|
1176
|
+
});
|
|
1177
|
+
}
|
|
1178
|
+
return {
|
|
1179
|
+
getFilterValue: JSON.stringify(result)
|
|
1180
|
+
};
|
|
1181
|
+
}
|
|
1182
|
+
/** @internal */
|
|
1183
|
+
function getFilterValue(filtersWithoutTimeType, timeColumn, timeFilter, filterSize, filtersLogicalOperator) {
|
|
1184
|
+
const result = Array(filterSize).fill(0);
|
|
1185
|
+
const featureFilter = _buildFeatureFilter({
|
|
1186
|
+
filters: filtersWithoutTimeType,
|
|
1187
|
+
type: 'number',
|
|
967
1188
|
filtersLogicalOperator
|
|
1189
|
+
});
|
|
1190
|
+
// We evaluate all filters except the time filter using _buildFeatureFilter function.
|
|
1191
|
+
// For the time filter, we return the value of the feature and we will change the getFilterRange result
|
|
1192
|
+
// every time this filter changes
|
|
1193
|
+
return feature => {
|
|
1194
|
+
result[0] = featureFilter(feature);
|
|
1195
|
+
if (timeColumn && timeFilter) {
|
|
1196
|
+
var _timeFilter$params3;
|
|
1197
|
+
const offsetBy = ((_timeFilter$params3 = timeFilter.params) == null ? void 0 : _timeFilter$params3.offsetBy) || 0;
|
|
1198
|
+
const f = feature.properties || feature;
|
|
1199
|
+
result[1] = f[timeColumn] - offsetBy;
|
|
1200
|
+
}
|
|
1201
|
+
return result;
|
|
968
1202
|
};
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
/**
|
|
1206
|
+
* Adds a {@link Filter} to the filter set. Any previous filters with the same
|
|
1207
|
+
* `column` and `type` will be replaced.
|
|
1208
|
+
*/
|
|
1209
|
+
function addFilter(filters, {
|
|
1210
|
+
column,
|
|
1211
|
+
type,
|
|
1212
|
+
values,
|
|
1213
|
+
owner
|
|
1214
|
+
}) {
|
|
1215
|
+
if (!filters[column]) {
|
|
1216
|
+
filters[column] = {};
|
|
973
1217
|
}
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
}
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
1218
|
+
const filter = {
|
|
1219
|
+
values,
|
|
1220
|
+
owner
|
|
1221
|
+
};
|
|
1222
|
+
filters[column][type] = filter;
|
|
1223
|
+
return filters;
|
|
1224
|
+
}
|
|
1225
|
+
/**
|
|
1226
|
+
* Removes one or more {@link Filter filters} from the filter set. If only
|
|
1227
|
+
* `column` is specified, then all filters on that column are removed. If both
|
|
1228
|
+
* `column` and `owner` are specified, then only filters for that column
|
|
1229
|
+
* associated with the owner are removed.
|
|
1230
|
+
*/
|
|
1231
|
+
function removeFilter(filters, {
|
|
1232
|
+
column,
|
|
1233
|
+
owner
|
|
1234
|
+
}) {
|
|
1235
|
+
const filter = filters[column];
|
|
1236
|
+
if (!filter) {
|
|
1237
|
+
return filters;
|
|
982
1238
|
}
|
|
983
|
-
if (
|
|
984
|
-
|
|
985
|
-
|
|
1239
|
+
if (owner) {
|
|
1240
|
+
for (const type of Object.values(FilterType)) {
|
|
1241
|
+
var _filter$type;
|
|
1242
|
+
if (owner === ((_filter$type = filter[type]) == null ? void 0 : _filter$type.owner)) {
|
|
1243
|
+
delete filter[type];
|
|
1244
|
+
}
|
|
986
1245
|
}
|
|
987
|
-
queryParams.spatialFiltersMode = spatialFiltersMode;
|
|
988
1246
|
}
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
if (isGet) {
|
|
992
|
-
url = urlWithSearchParams;
|
|
1247
|
+
if (!owner || isEmptyObject(filter)) {
|
|
1248
|
+
delete filters[column];
|
|
993
1249
|
}
|
|
994
|
-
return
|
|
995
|
-
url,
|
|
996
|
-
accessToken: source.accessToken,
|
|
997
|
-
opts: _extends({}, opts, {
|
|
998
|
-
method: isGet ? 'GET' : 'POST'
|
|
999
|
-
}, !isGet && {
|
|
1000
|
-
body: JSON.stringify(queryParams)
|
|
1001
|
-
})
|
|
1002
|
-
});
|
|
1250
|
+
return filters;
|
|
1003
1251
|
}
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1252
|
+
/**
|
|
1253
|
+
* Clears all {@link Filter filters} from the filter set.
|
|
1254
|
+
*/
|
|
1255
|
+
function clearFilters(filters) {
|
|
1256
|
+
for (const column of Object.keys(filters)) {
|
|
1257
|
+
delete filters[column];
|
|
1258
|
+
}
|
|
1259
|
+
return filters;
|
|
1260
|
+
}
|
|
1261
|
+
function hasFilter(filters, {
|
|
1262
|
+
column,
|
|
1263
|
+
owner
|
|
1264
|
+
}) {
|
|
1265
|
+
const filter = filters[column];
|
|
1266
|
+
if (!filter) {
|
|
1267
|
+
return false;
|
|
1268
|
+
}
|
|
1269
|
+
if (!owner) {
|
|
1270
|
+
return true;
|
|
1271
|
+
}
|
|
1272
|
+
for (const type of Object.values(FilterType)) {
|
|
1273
|
+
var _filter$type2;
|
|
1274
|
+
if (owner === ((_filter$type2 = filter[type]) == null ? void 0 : _filter$type2.owner)) {
|
|
1275
|
+
return true;
|
|
1015
1276
|
}
|
|
1016
1277
|
}
|
|
1017
|
-
return
|
|
1278
|
+
return false;
|
|
1279
|
+
}
|
|
1280
|
+
function getFilter(filters, {
|
|
1281
|
+
column,
|
|
1282
|
+
type,
|
|
1283
|
+
owner
|
|
1284
|
+
}) {
|
|
1285
|
+
var _filter$type3;
|
|
1286
|
+
const filter = filters[column];
|
|
1287
|
+
if (!filter) {
|
|
1288
|
+
return null;
|
|
1289
|
+
}
|
|
1290
|
+
if (!owner || owner === ((_filter$type3 = filter[type]) == null ? void 0 : _filter$type3.owner)) {
|
|
1291
|
+
return filter[type] || null;
|
|
1292
|
+
}
|
|
1293
|
+
return null;
|
|
1018
1294
|
}
|
|
1019
1295
|
|
|
1020
|
-
const _excluded$2 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
|
|
1021
|
-
_excluded2 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
|
|
1022
|
-
_excluded3 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController", "operationExp"],
|
|
1023
|
-
_excluded4 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
|
|
1024
|
-
_excluded5 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
|
|
1025
|
-
_excluded6 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
|
|
1026
|
-
_excluded7 = ["filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
|
|
1027
|
-
_excluded8 = ["filterOwner", "abortController", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState"];
|
|
1028
1296
|
/**
|
|
1029
|
-
*
|
|
1297
|
+
* Returns a {@link SpatialFilter} for a given viewport, typically obtained
|
|
1298
|
+
* from deck.gl's `viewport.getBounds()` method ([west, south, east, north]).
|
|
1299
|
+
* If the viewport covers the entire world (to some margin of error in Web
|
|
1300
|
+
* Mercator space), `undefined` is returned instead.
|
|
1030
1301
|
*
|
|
1031
|
-
*
|
|
1302
|
+
* If the viewport extends beyond longitude range [-180, +180], the polygon
|
|
1303
|
+
* may be reformatted for compatibility with CARTO APIs.
|
|
1032
1304
|
*/
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
filterOwner,
|
|
1037
|
-
spatialFilter,
|
|
1038
|
-
spatialFiltersMode,
|
|
1039
|
-
spatialIndexReferenceViewState,
|
|
1040
|
-
abortController
|
|
1041
|
-
} = options,
|
|
1042
|
-
params = _objectWithoutPropertiesLoose(options, _excluded$2);
|
|
1043
|
-
const {
|
|
1044
|
-
column,
|
|
1045
|
-
operation,
|
|
1046
|
-
operationColumn
|
|
1047
|
-
} = params;
|
|
1048
|
-
const source = this.getModelSource(filterOwner);
|
|
1049
|
-
const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
1050
|
-
return executeModel({
|
|
1051
|
-
model: 'category',
|
|
1052
|
-
source: _extends({}, source, {
|
|
1053
|
-
spatialFiltersResolution,
|
|
1054
|
-
spatialFiltersMode,
|
|
1055
|
-
spatialFilter
|
|
1056
|
-
}),
|
|
1057
|
-
params: {
|
|
1058
|
-
column,
|
|
1059
|
-
operation,
|
|
1060
|
-
operationColumn: operationColumn || column
|
|
1061
|
-
},
|
|
1062
|
-
opts: {
|
|
1063
|
-
abortController
|
|
1064
|
-
}
|
|
1065
|
-
}).then(res => normalizeObjectKeys(res.rows));
|
|
1066
|
-
}
|
|
1067
|
-
async getFeatures(options) {
|
|
1068
|
-
const {
|
|
1069
|
-
filterOwner,
|
|
1070
|
-
spatialFilter,
|
|
1071
|
-
spatialFiltersMode,
|
|
1072
|
-
spatialIndexReferenceViewState,
|
|
1073
|
-
abortController
|
|
1074
|
-
} = options,
|
|
1075
|
-
params = _objectWithoutPropertiesLoose(options, _excluded2);
|
|
1076
|
-
const {
|
|
1077
|
-
columns,
|
|
1078
|
-
dataType,
|
|
1079
|
-
featureIds,
|
|
1080
|
-
z,
|
|
1081
|
-
limit,
|
|
1082
|
-
tileResolution
|
|
1083
|
-
} = params;
|
|
1084
|
-
const source = this.getModelSource(filterOwner);
|
|
1085
|
-
const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
1086
|
-
return executeModel({
|
|
1087
|
-
model: 'pick',
|
|
1088
|
-
source: _extends({}, source, {
|
|
1089
|
-
spatialFiltersResolution,
|
|
1090
|
-
spatialFiltersMode,
|
|
1091
|
-
spatialFilter
|
|
1092
|
-
}),
|
|
1093
|
-
params: {
|
|
1094
|
-
columns,
|
|
1095
|
-
dataType,
|
|
1096
|
-
featureIds,
|
|
1097
|
-
z,
|
|
1098
|
-
limit: limit || 1000,
|
|
1099
|
-
tileResolution: tileResolution || DEFAULT_TILE_RESOLUTION
|
|
1100
|
-
},
|
|
1101
|
-
opts: {
|
|
1102
|
-
abortController
|
|
1103
|
-
}
|
|
1104
|
-
// Avoid `normalizeObjectKeys()`, which changes column names.
|
|
1105
|
-
}).then(({
|
|
1106
|
-
rows
|
|
1107
|
-
}) => ({
|
|
1108
|
-
rows
|
|
1109
|
-
}));
|
|
1110
|
-
}
|
|
1111
|
-
async getFormula(options) {
|
|
1112
|
-
const {
|
|
1113
|
-
filterOwner,
|
|
1114
|
-
spatialFilter,
|
|
1115
|
-
spatialFiltersMode,
|
|
1116
|
-
spatialIndexReferenceViewState,
|
|
1117
|
-
abortController,
|
|
1118
|
-
operationExp
|
|
1119
|
-
} = options,
|
|
1120
|
-
params = _objectWithoutPropertiesLoose(options, _excluded3);
|
|
1121
|
-
const {
|
|
1122
|
-
column,
|
|
1123
|
-
operation
|
|
1124
|
-
} = params;
|
|
1125
|
-
const source = this.getModelSource(filterOwner);
|
|
1126
|
-
const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
1127
|
-
return executeModel({
|
|
1128
|
-
model: 'formula',
|
|
1129
|
-
source: _extends({}, source, {
|
|
1130
|
-
spatialFiltersResolution,
|
|
1131
|
-
spatialFiltersMode,
|
|
1132
|
-
spatialFilter
|
|
1133
|
-
}),
|
|
1134
|
-
params: {
|
|
1135
|
-
column: column != null ? column : '*',
|
|
1136
|
-
operation: operation != null ? operation : 'count',
|
|
1137
|
-
operationExp
|
|
1138
|
-
},
|
|
1139
|
-
opts: {
|
|
1140
|
-
abortController
|
|
1141
|
-
}
|
|
1142
|
-
}).then(res => normalizeObjectKeys(res.rows[0]));
|
|
1143
|
-
}
|
|
1144
|
-
async getHistogram(options) {
|
|
1145
|
-
const {
|
|
1146
|
-
filterOwner,
|
|
1147
|
-
spatialFilter,
|
|
1148
|
-
spatialFiltersMode,
|
|
1149
|
-
spatialIndexReferenceViewState,
|
|
1150
|
-
abortController
|
|
1151
|
-
} = options,
|
|
1152
|
-
params = _objectWithoutPropertiesLoose(options, _excluded4);
|
|
1153
|
-
const {
|
|
1154
|
-
column,
|
|
1155
|
-
operation,
|
|
1156
|
-
ticks
|
|
1157
|
-
} = params;
|
|
1158
|
-
const source = this.getModelSource(filterOwner);
|
|
1159
|
-
const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
1160
|
-
const data = await executeModel({
|
|
1161
|
-
model: 'histogram',
|
|
1162
|
-
source: _extends({}, source, {
|
|
1163
|
-
spatialFiltersResolution,
|
|
1164
|
-
spatialFiltersMode,
|
|
1165
|
-
spatialFilter
|
|
1166
|
-
}),
|
|
1167
|
-
params: {
|
|
1168
|
-
column,
|
|
1169
|
-
operation,
|
|
1170
|
-
ticks
|
|
1171
|
-
},
|
|
1172
|
-
opts: {
|
|
1173
|
-
abortController
|
|
1174
|
-
}
|
|
1175
|
-
}).then(res => normalizeObjectKeys(res.rows));
|
|
1176
|
-
if (data.length) {
|
|
1177
|
-
// Given N ticks the API returns up to N+1 bins, omitting any empty bins. Bins
|
|
1178
|
-
// include 1 bin below the lowest tick, N-1 between ticks, and 1 bin above the highest tick.
|
|
1179
|
-
const result = Array(ticks.length + 1).fill(0);
|
|
1180
|
-
data.forEach(({
|
|
1181
|
-
tick,
|
|
1182
|
-
value
|
|
1183
|
-
}) => result[tick] = value);
|
|
1184
|
-
return result;
|
|
1185
|
-
}
|
|
1186
|
-
return [];
|
|
1187
|
-
}
|
|
1188
|
-
async getRange(options) {
|
|
1189
|
-
const {
|
|
1190
|
-
filterOwner,
|
|
1191
|
-
spatialFilter,
|
|
1192
|
-
spatialFiltersMode,
|
|
1193
|
-
spatialIndexReferenceViewState,
|
|
1194
|
-
abortController
|
|
1195
|
-
} = options,
|
|
1196
|
-
params = _objectWithoutPropertiesLoose(options, _excluded5);
|
|
1197
|
-
const {
|
|
1198
|
-
column
|
|
1199
|
-
} = params;
|
|
1200
|
-
const source = this.getModelSource(filterOwner);
|
|
1201
|
-
const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
1202
|
-
return executeModel({
|
|
1203
|
-
model: 'range',
|
|
1204
|
-
source: _extends({}, source, {
|
|
1205
|
-
spatialFiltersResolution,
|
|
1206
|
-
spatialFiltersMode,
|
|
1207
|
-
spatialFilter
|
|
1208
|
-
}),
|
|
1209
|
-
params: {
|
|
1210
|
-
column
|
|
1211
|
-
},
|
|
1212
|
-
opts: {
|
|
1213
|
-
abortController
|
|
1214
|
-
}
|
|
1215
|
-
}).then(res => normalizeObjectKeys(res.rows[0]));
|
|
1216
|
-
}
|
|
1217
|
-
async getScatter(options) {
|
|
1218
|
-
const {
|
|
1219
|
-
filterOwner,
|
|
1220
|
-
spatialFilter,
|
|
1221
|
-
spatialFiltersMode,
|
|
1222
|
-
spatialIndexReferenceViewState,
|
|
1223
|
-
abortController
|
|
1224
|
-
} = options,
|
|
1225
|
-
params = _objectWithoutPropertiesLoose(options, _excluded6);
|
|
1226
|
-
const {
|
|
1227
|
-
xAxisColumn,
|
|
1228
|
-
xAxisJoinOperation,
|
|
1229
|
-
yAxisColumn,
|
|
1230
|
-
yAxisJoinOperation
|
|
1231
|
-
} = params;
|
|
1232
|
-
const source = this.getModelSource(filterOwner);
|
|
1233
|
-
const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
1234
|
-
// Make sure this is sync with the same constant in cloud-native/maps-api
|
|
1235
|
-
const HARD_LIMIT = 500;
|
|
1236
|
-
return executeModel({
|
|
1237
|
-
model: 'scatterplot',
|
|
1238
|
-
source: _extends({}, source, {
|
|
1239
|
-
spatialFiltersResolution,
|
|
1240
|
-
spatialFiltersMode,
|
|
1241
|
-
spatialFilter
|
|
1242
|
-
}),
|
|
1243
|
-
params: {
|
|
1244
|
-
xAxisColumn,
|
|
1245
|
-
xAxisJoinOperation,
|
|
1246
|
-
yAxisColumn,
|
|
1247
|
-
yAxisJoinOperation,
|
|
1248
|
-
limit: HARD_LIMIT
|
|
1249
|
-
},
|
|
1250
|
-
opts: {
|
|
1251
|
-
abortController
|
|
1252
|
-
}
|
|
1253
|
-
}).then(res => normalizeObjectKeys(res.rows)).then(res => res.map(({
|
|
1254
|
-
x,
|
|
1255
|
-
y
|
|
1256
|
-
}) => [x, y]));
|
|
1257
|
-
}
|
|
1258
|
-
async getTable(options) {
|
|
1259
|
-
const {
|
|
1260
|
-
filterOwner,
|
|
1261
|
-
spatialFilter,
|
|
1262
|
-
spatialFiltersMode,
|
|
1263
|
-
spatialIndexReferenceViewState,
|
|
1264
|
-
abortController
|
|
1265
|
-
} = options,
|
|
1266
|
-
params = _objectWithoutPropertiesLoose(options, _excluded7);
|
|
1267
|
-
const {
|
|
1268
|
-
columns,
|
|
1269
|
-
sortBy,
|
|
1270
|
-
sortDirection,
|
|
1271
|
-
offset = 0,
|
|
1272
|
-
limit = 10
|
|
1273
|
-
} = params;
|
|
1274
|
-
const source = this.getModelSource(filterOwner);
|
|
1275
|
-
const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
1276
|
-
return executeModel({
|
|
1277
|
-
model: 'table',
|
|
1278
|
-
source: _extends({}, source, {
|
|
1279
|
-
spatialFiltersResolution,
|
|
1280
|
-
spatialFiltersMode,
|
|
1281
|
-
spatialFilter
|
|
1282
|
-
}),
|
|
1283
|
-
params: {
|
|
1284
|
-
column: columns,
|
|
1285
|
-
sortBy,
|
|
1286
|
-
sortDirection,
|
|
1287
|
-
limit,
|
|
1288
|
-
offset
|
|
1289
|
-
},
|
|
1290
|
-
opts: {
|
|
1291
|
-
abortController
|
|
1292
|
-
}
|
|
1293
|
-
}).then(res => {
|
|
1294
|
-
var _res$rows, _res$metadata$total, _res$metadata, _res$METADATA;
|
|
1295
|
-
return {
|
|
1296
|
-
// Avoid `normalizeObjectKeys()`, which changes column names.
|
|
1297
|
-
rows: (_res$rows = res.rows) != null ? _res$rows : res.ROWS,
|
|
1298
|
-
totalCount: (_res$metadata$total = (_res$metadata = res.metadata) == null ? void 0 : _res$metadata.total) != null ? _res$metadata$total : (_res$METADATA = res.METADATA) == null ? void 0 : _res$METADATA.TOTAL
|
|
1299
|
-
};
|
|
1300
|
-
});
|
|
1301
|
-
}
|
|
1302
|
-
async getTimeSeries(options) {
|
|
1303
|
-
const {
|
|
1304
|
-
filterOwner,
|
|
1305
|
-
abortController,
|
|
1306
|
-
spatialFilter,
|
|
1307
|
-
spatialFiltersMode,
|
|
1308
|
-
spatialIndexReferenceViewState
|
|
1309
|
-
} = options,
|
|
1310
|
-
params = _objectWithoutPropertiesLoose(options, _excluded8);
|
|
1311
|
-
const {
|
|
1312
|
-
column,
|
|
1313
|
-
operationColumn,
|
|
1314
|
-
joinOperation,
|
|
1315
|
-
operation,
|
|
1316
|
-
stepSize,
|
|
1317
|
-
stepMultiplier,
|
|
1318
|
-
splitByCategory,
|
|
1319
|
-
splitByCategoryLimit,
|
|
1320
|
-
splitByCategoryValues
|
|
1321
|
-
} = params;
|
|
1322
|
-
const source = this.getModelSource(filterOwner);
|
|
1323
|
-
const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
1324
|
-
return executeModel({
|
|
1325
|
-
model: 'timeseries',
|
|
1326
|
-
source: _extends({}, source, {
|
|
1327
|
-
spatialFiltersResolution,
|
|
1328
|
-
spatialFiltersMode,
|
|
1329
|
-
spatialFilter
|
|
1330
|
-
}),
|
|
1331
|
-
params: {
|
|
1332
|
-
column,
|
|
1333
|
-
stepSize,
|
|
1334
|
-
stepMultiplier,
|
|
1335
|
-
operationColumn: operationColumn || column,
|
|
1336
|
-
joinOperation,
|
|
1337
|
-
operation,
|
|
1338
|
-
splitByCategory,
|
|
1339
|
-
splitByCategoryLimit,
|
|
1340
|
-
splitByCategoryValues
|
|
1341
|
-
},
|
|
1342
|
-
opts: {
|
|
1343
|
-
abortController
|
|
1344
|
-
}
|
|
1345
|
-
}).then(res => {
|
|
1346
|
-
var _res$metadata2;
|
|
1347
|
-
return {
|
|
1348
|
-
rows: normalizeObjectKeys(res.rows),
|
|
1349
|
-
categories: (_res$metadata2 = res.metadata) == null ? void 0 : _res$metadata2.categories
|
|
1350
|
-
};
|
|
1351
|
-
});
|
|
1305
|
+
function createViewportSpatialFilter(viewport) {
|
|
1306
|
+
if (_isGlobalViewport(viewport)) {
|
|
1307
|
+
return;
|
|
1352
1308
|
}
|
|
1309
|
+
return createPolygonSpatialFilter(bboxPolygon(viewport).geometry);
|
|
1310
|
+
}
|
|
1311
|
+
/**
|
|
1312
|
+
* Returns a {@link SpatialFilter} for a given {@link Polygon} or
|
|
1313
|
+
* {@link MultiPolygon}. If the polygon(s) extend outside longitude
|
|
1314
|
+
* range [-180, +180], the result may be reformatted for compatibility
|
|
1315
|
+
* with CARTO APIs.
|
|
1316
|
+
*/
|
|
1317
|
+
function createPolygonSpatialFilter(spatialFilter) {
|
|
1318
|
+
return spatialFilter && _normalizeGeometry(spatialFilter) || undefined;
|
|
1353
1319
|
}
|
|
1354
|
-
|
|
1355
1320
|
/**
|
|
1356
|
-
*
|
|
1357
|
-
*
|
|
1358
|
-
* Generally not intended to be constructed directly. Instead, call
|
|
1359
|
-
* {@link vectorQuerySource}, {@link h3QuerySource}, or {@link quadbinQuerySource},
|
|
1360
|
-
* which can be shared with map layers. Sources contain a `widgetSource` property,
|
|
1361
|
-
* for use by widget implementations.
|
|
1362
|
-
*
|
|
1363
|
-
* Example:
|
|
1321
|
+
* Check if a viewport is large enough to represent a global coverage.
|
|
1322
|
+
* In this case the spatial filter parameter for widget calculation is removed.
|
|
1364
1323
|
*
|
|
1365
|
-
*
|
|
1366
|
-
|
|
1324
|
+
* @privateRemarks Source: @carto/react-core
|
|
1325
|
+
*/
|
|
1326
|
+
function _isGlobalViewport(viewport) {
|
|
1327
|
+
const [minx, miny, maxx, maxy] = viewport;
|
|
1328
|
+
return maxx - minx > 179.5 * 2 && maxy - miny > 85.05 * 2;
|
|
1329
|
+
}
|
|
1330
|
+
/**
|
|
1331
|
+
* Normalized a geometry, coming from a mask or a viewport. The parts
|
|
1332
|
+
* spanning outside longitude range [-180, +180] are clipped and "folded"
|
|
1333
|
+
* back to the valid range and unioned to the polygons inide that range.
|
|
1367
1334
|
*
|
|
1368
|
-
*
|
|
1369
|
-
* accessToken: '••••',
|
|
1370
|
-
* connectionName: 'carto_dw',
|
|
1371
|
-
* sqlQuery: 'SELECT * FROM carto-demo-data.demo_tables.retail_stores'
|
|
1372
|
-
* });
|
|
1335
|
+
* It results in a Polygon or MultiPolygon strictly inside the validity range.
|
|
1373
1336
|
*
|
|
1374
|
-
*
|
|
1375
|
-
* ```
|
|
1337
|
+
* @privateRemarks Source: @carto/react-core
|
|
1376
1338
|
*/
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
if (val[0] === undefined || val[0] === null) {
|
|
1390
|
-
return [Number.MIN_SAFE_INTEGER, val[1]];
|
|
1339
|
+
function _normalizeGeometry(geometry) {
|
|
1340
|
+
const WORLD = [-180, -90, +180, +90];
|
|
1341
|
+
const worldClip = _clean(bboxClip(geometry, WORLD).geometry);
|
|
1342
|
+
const geometryTxWest = _tx(geometry, 360);
|
|
1343
|
+
const geometryTxEast = _tx(geometry, -360);
|
|
1344
|
+
let result = worldClip;
|
|
1345
|
+
if (result && geometryTxWest) {
|
|
1346
|
+
const worldWestClip = _clean(bboxClip(geometryTxWest, WORLD).geometry);
|
|
1347
|
+
if (worldWestClip) {
|
|
1348
|
+
const collection = featureCollection([feature(result), feature(worldWestClip)]);
|
|
1349
|
+
const merged = union(collection);
|
|
1350
|
+
result = merged ? _clean(merged.geometry) : result;
|
|
1391
1351
|
}
|
|
1392
|
-
|
|
1393
|
-
|
|
1352
|
+
}
|
|
1353
|
+
if (result && geometryTxEast) {
|
|
1354
|
+
const worldEastClip = _clean(bboxClip(geometryTxEast, WORLD).geometry);
|
|
1355
|
+
if (worldEastClip) {
|
|
1356
|
+
const collection = featureCollection([feature(result), feature(worldEastClip)]);
|
|
1357
|
+
const merged = union(collection);
|
|
1358
|
+
result = merged ? _clean(merged.geometry) : result;
|
|
1394
1359
|
}
|
|
1395
|
-
return val;
|
|
1396
|
-
});
|
|
1397
|
-
}
|
|
1398
|
-
|
|
1399
|
-
const filterFunctions = {
|
|
1400
|
-
[FilterType.IN]: filterIn,
|
|
1401
|
-
[FilterType.BETWEEN]: filterBetween,
|
|
1402
|
-
[FilterType.TIME]: filterTime,
|
|
1403
|
-
[FilterType.CLOSED_OPEN]: filterClosedOpen,
|
|
1404
|
-
[FilterType.STRING_SEARCH]: filterStringSearch
|
|
1405
|
-
};
|
|
1406
|
-
function filterIn(filterValues, featureValue) {
|
|
1407
|
-
return filterValues.includes(featureValue);
|
|
1408
|
-
}
|
|
1409
|
-
// FilterTypes.BETWEEN
|
|
1410
|
-
function filterBetween(filterValues, featureValue) {
|
|
1411
|
-
const checkRange = range => {
|
|
1412
|
-
const [lowerBound, upperBound] = range;
|
|
1413
|
-
return featureValue >= lowerBound && featureValue <= upperBound;
|
|
1414
|
-
};
|
|
1415
|
-
return makeIntervalComplete(filterValues).some(checkRange);
|
|
1416
|
-
}
|
|
1417
|
-
function filterTime(filterValues, featureValue) {
|
|
1418
|
-
const featureValueAsTimestamp = new Date(featureValue).getTime();
|
|
1419
|
-
if (isFinite(featureValueAsTimestamp)) {
|
|
1420
|
-
return filterBetween(filterValues, featureValueAsTimestamp);
|
|
1421
|
-
} else {
|
|
1422
|
-
throw new Error(`Column used to filter by time isn't well formatted.`);
|
|
1423
1360
|
}
|
|
1361
|
+
return result;
|
|
1424
1362
|
}
|
|
1425
|
-
|
|
1426
|
-
function
|
|
1427
|
-
const
|
|
1428
|
-
|
|
1429
|
-
return featureValue >= lowerBound && featureValue < upperBound;
|
|
1430
|
-
};
|
|
1431
|
-
return makeIntervalComplete(filterValues).some(checkRange);
|
|
1432
|
-
}
|
|
1433
|
-
// FilterTypes.STRING_SEARCH
|
|
1434
|
-
function filterStringSearch(filterValues, featureValue, params = {}) {
|
|
1435
|
-
const normalizedFeatureValue = normalize(featureValue, params);
|
|
1436
|
-
const stringRegExp = params.useRegExp ? filterValues : filterValues.map(filterValue => {
|
|
1437
|
-
let stringRegExp = escapeRegExp(normalize(filterValue, params));
|
|
1438
|
-
if (params.mustStart) stringRegExp = `^${stringRegExp}`;
|
|
1439
|
-
if (params.mustEnd) stringRegExp = `${stringRegExp}$`;
|
|
1440
|
-
return stringRegExp;
|
|
1441
|
-
});
|
|
1442
|
-
const regex = new RegExp(stringRegExp.join('|'), params.caseSensitive ? 'g' : 'gi');
|
|
1443
|
-
return !!normalizedFeatureValue.match(regex);
|
|
1444
|
-
}
|
|
1445
|
-
// Aux
|
|
1446
|
-
const specialCharRegExp = /[.*+?^${}()|[\]\\]/g;
|
|
1447
|
-
const normalizeRegExp = /(?:[\^`\xA8\xAF\xB4\xB7\xB8\u02B0-\u034E\u0350-\u0357\u035D-\u0362\u0374\u0375\u037A\u0384\u0385\u0483-\u0487\u0559\u0591-\u05A1\u05A3-\u05BD\u05BF\u05C1\u05C2\u05C4\u064B-\u0652\u0657\u0658\u06DF\u06E0\u06E5\u06E6\u06EA-\u06EC\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F5\u0818\u0819\u0898-\u089F\u08C9-\u08D2\u08E3-\u08FE\u093C\u094D\u0951-\u0954\u0971\u09BC\u09CD\u0A3C\u0A4D\u0ABC\u0ACD\u0AFD-\u0AFF\u0B3C\u0B4D\u0B55\u0BCD\u0C3C\u0C4D\u0CBC\u0CCD\u0D3B\u0D3C\u0D4D\u0DCA\u0E3A\u0E47-\u0E4C\u0E4E\u0EBA\u0EC8-\u0ECC\u0F18\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F82-\u0F84\u0F86\u0F87\u0FC6\u1037\u1039\u103A\u1063\u1064\u1069-\u106D\u1087-\u108D\u108F\u109A\u109B\u135D-\u135F\u1714\u1715\u1734\u17C9-\u17D3\u17DD\u1939-\u193B\u1A60\u1A75-\u1A7C\u1A7F\u1AB0-\u1ABE\u1AC1-\u1ACB\u1B34\u1B44\u1B6B-\u1B73\u1BAA\u1BAB\u1BE6\u1BF2\u1BF3\u1C36\u1C37\u1C78-\u1C7D\u1CD0-\u1CE8\u1CED\u1CF4\u1CF7-\u1CF9\u1D2C-\u1D6A\u1DC4-\u1DCF\u1DF5-\u1DFF\u1FBD\u1FBF-\u1FC1\u1FCD-\u1FCF\u1FDD-\u1FDF\u1FED-\u1FEF\u1FFD\u1FFE\u2CEF-\u2CF1\u2E2F\u302A-\u302F\u3099-\u309C\u30FC\uA66F\uA67C\uA67D\uA67F\uA69C\uA69D\uA6F0\uA6F1\uA700-\uA721\uA788-\uA78A\uA7F8\uA7F9\uA806\uA82C\uA8C4\uA8E0-\uA8F1\uA92B-\uA92E\uA953\uA9B3\uA9C0\uA9E5\uAA7B-\uAA7D\uAABF-\uAAC2\uAAF6\uAB5B-\uAB5F\uAB69-\uAB6B\uABEC\uABED\uFB1E\uFE20-\uFE2F\uFF3E\uFF40\uFF70\uFF9E\uFF9F\uFFE3]|\uD800\uDEE0|\uD801[\uDF80-\uDF85\uDF87-\uDFB0\uDFB2-\uDFBA]|\uD802[\uDE38-\uDE3A\uDE3F\uDEE5\uDEE6]|\uD803[\uDD22-\uDD27\uDD4E\uDD69-\uDD6D\uDEFD-\uDEFF\uDF46-\uDF50\uDF82-\uDF85]|\uD804[\uDC46\uDC70\uDCB9\uDCBA\uDD33\uDD34\uDD73\uDDC0\uDDCA-\uDDCC\uDE35\uDE36\uDEE9\uDEEA\uDF3B\uDF3C\uDF4D\uDF66-\uDF6C\uDF70-\uDF74\uDFCE-\uDFD0\uDFD2\uDFD3\uDFE1\uDFE2]|\uD805[\uDC42\uDC46\uDCC2\uDCC3\uDDBF\uDDC0\uDE3F\uDEB6\uDEB7\uDF2B]|\uD806[\uDC39\uDC3A\uDD3D\uDD3E\uDD43\uDDE0\uDE34\uDE47\uDE99]|\uD807[\uDC3F\uDD42\uDD44\uDD45\uDD97\uDF41\uDF42\uDF5A]|\uD80D[\uDC47-\uDC55]|\uD818\uDD2F|\uD81A[\uDEF0-\uDEF4\uDF30-\uDF36]|\uD81B[\uDD6B\uDD6C\uDF8F-\uDF9F\uDFF0\uDFF1]|\uD82B[\uDFF0-\uDFF3\uDFF5-\uDFFB\uDFFD\uDFFE]|\uD833[\uDF00-\uDF2D\uDF30-\uDF46]|\uD834[\uDD67-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD]|\uD838[\uDC30-\uDC6D\uDD30-\uDD36\uDEAE\uDEEC-\uDEEF]|\uD839[\uDDEE\uDDEF]|\uD83A[\uDCD0-\uDCD6\uDD44-\uDD46\uDD48-\uDD4A])/g;
|
|
1448
|
-
function escapeRegExp(value) {
|
|
1449
|
-
return value.replace(specialCharRegExp, '\\$&');
|
|
1450
|
-
}
|
|
1451
|
-
function normalize(data, params) {
|
|
1452
|
-
let normalizedData = String(data);
|
|
1453
|
-
if (!params.keepSpecialCharacters) normalizedData = normalizedData.normalize('NFD').replace(normalizeRegExp, '');
|
|
1454
|
-
return normalizedData;
|
|
1363
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
1364
|
+
function _cleanPolygonCoords(cc) {
|
|
1365
|
+
const coords = cc.filter(c => c.length > 0);
|
|
1366
|
+
return coords.length > 0 ? coords : null;
|
|
1455
1367
|
}
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
};
|
|
1461
|
-
function passesFilter(columns, filters, feature, filtersLogicalOperator) {
|
|
1462
|
-
const method = LOGICAL_OPERATOR_METHODS[filtersLogicalOperator];
|
|
1463
|
-
return columns[method](column => {
|
|
1464
|
-
const columnFilters = filters[column];
|
|
1465
|
-
const columnFilterTypes = Object.keys(columnFilters);
|
|
1466
|
-
if (!feature || feature[column] === null || feature[column] === undefined) {
|
|
1467
|
-
return false;
|
|
1468
|
-
}
|
|
1469
|
-
return columnFilterTypes.every(filter => {
|
|
1470
|
-
const filterFunction = filterFunctions[filter];
|
|
1471
|
-
if (!filterFunction) {
|
|
1472
|
-
throw new Error(`"${filter}" filter is not implemented.`);
|
|
1473
|
-
}
|
|
1474
|
-
return filterFunction(columnFilters[filter].values, feature[column], columnFilters[filter].params);
|
|
1475
|
-
});
|
|
1476
|
-
});
|
|
1368
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
1369
|
+
function _cleanMultiPolygonCoords(ccc) {
|
|
1370
|
+
const coords = ccc.map(_cleanPolygonCoords).filter(cc => cc);
|
|
1371
|
+
return coords.length > 0 ? coords : null;
|
|
1477
1372
|
}
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
}) {
|
|
1483
|
-
const columns = Object.keys(filters);
|
|
1484
|
-
if (!columns.length) {
|
|
1485
|
-
return () => type === 'number' ? 1 : true;
|
|
1373
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
1374
|
+
function _clean(geometry) {
|
|
1375
|
+
if (!geometry) {
|
|
1376
|
+
return null;
|
|
1486
1377
|
}
|
|
1487
|
-
|
|
1488
|
-
const
|
|
1489
|
-
|
|
1490
|
-
return type === 'number' ? Number(featurePassesFilter) : featurePassesFilter;
|
|
1491
|
-
};
|
|
1492
|
-
}
|
|
1493
|
-
// Apply certain filters to a collection of features
|
|
1494
|
-
function applyFilters(features, filters, filtersLogicalOperator) {
|
|
1495
|
-
return Object.keys(filters).length ? features.filter(buildFeatureFilter({
|
|
1496
|
-
filters,
|
|
1497
|
-
filtersLogicalOperator
|
|
1498
|
-
})) : features;
|
|
1499
|
-
}
|
|
1500
|
-
// Binary
|
|
1501
|
-
function buildBinaryFeatureFilter({
|
|
1502
|
-
filters = {}
|
|
1503
|
-
}) {
|
|
1504
|
-
const columns = Object.keys(filters);
|
|
1505
|
-
if (!columns.length) {
|
|
1506
|
-
return () => 1;
|
|
1378
|
+
if (_isPolygon(geometry)) {
|
|
1379
|
+
const coords = _cleanPolygonCoords(geometry.coordinates);
|
|
1380
|
+
return coords ? polygon(coords).geometry : null;
|
|
1507
1381
|
}
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
column
|
|
1512
|
-
}) {
|
|
1513
|
-
var _binaryData$numericPr;
|
|
1514
|
-
return (_binaryData$numericPr = binaryData.numericProps) == null || (_binaryData$numericPr = _binaryData$numericPr[column]) == null ? void 0 : _binaryData$numericPr.value[featureIdIdx];
|
|
1515
|
-
}
|
|
1516
|
-
function getValueFromProperties(featureIdIdx, binaryData, {
|
|
1517
|
-
column
|
|
1518
|
-
}) {
|
|
1519
|
-
var _binaryData$propertie;
|
|
1520
|
-
const propertyIdx = binaryData.featureIds.value[featureIdIdx];
|
|
1521
|
-
return (_binaryData$propertie = binaryData.properties[propertyIdx]) == null ? void 0 : _binaryData$propertie[column];
|
|
1522
|
-
}
|
|
1523
|
-
const GET_VALUE_BY_BINARY_PROP = {
|
|
1524
|
-
properties: getValueFromProperties,
|
|
1525
|
-
numericProps: getValueFromNumericProps
|
|
1526
|
-
};
|
|
1527
|
-
function getBinaryPropertyByFilterValues(filterValues) {
|
|
1528
|
-
return typeof filterValues.flat()[0] === 'string' ? 'properties' : 'numericProps';
|
|
1529
|
-
}
|
|
1530
|
-
function getFeatureValue(featureIdIdx, binaryData, filter) {
|
|
1531
|
-
const {
|
|
1532
|
-
column,
|
|
1533
|
-
values
|
|
1534
|
-
} = filter;
|
|
1535
|
-
const binaryProp = getBinaryPropertyByFilterValues(values);
|
|
1536
|
-
const getFeatureValueFn = GET_VALUE_BY_BINARY_PROP[binaryProp];
|
|
1537
|
-
return getFeatureValueFn(featureIdIdx, binaryData, {
|
|
1538
|
-
column
|
|
1539
|
-
});
|
|
1540
|
-
}
|
|
1541
|
-
function passesFilterUsingBinary(columns, filters, featureIdIdx, binaryData) {
|
|
1542
|
-
return columns.every(column => {
|
|
1543
|
-
const columnFilters = filters[column];
|
|
1544
|
-
return Object.entries(columnFilters).every(([type, {
|
|
1545
|
-
values
|
|
1546
|
-
}]) => {
|
|
1547
|
-
const filterFn = filterFunctions[type];
|
|
1548
|
-
if (!filterFn) {
|
|
1549
|
-
throw new Error(`"${type}" filter is not implemented.`);
|
|
1550
|
-
}
|
|
1551
|
-
if (!values) return 0;
|
|
1552
|
-
const featureValue = getFeatureValue(featureIdIdx, binaryData, {
|
|
1553
|
-
type: type,
|
|
1554
|
-
column,
|
|
1555
|
-
values
|
|
1556
|
-
});
|
|
1557
|
-
if (featureValue === undefined || featureValue === null) return 0;
|
|
1558
|
-
return filterFn(values, featureValue);
|
|
1559
|
-
});
|
|
1560
|
-
});
|
|
1561
|
-
}
|
|
1562
|
-
|
|
1563
|
-
function geojsonFeatures({
|
|
1564
|
-
geojson,
|
|
1565
|
-
spatialFilter,
|
|
1566
|
-
uniqueIdProperty
|
|
1567
|
-
}) {
|
|
1568
|
-
let uniqueIdx = 0;
|
|
1569
|
-
const map = new Map();
|
|
1570
|
-
if (!spatialFilter) {
|
|
1571
|
-
return [];
|
|
1382
|
+
if (_isMultiPolygon(geometry)) {
|
|
1383
|
+
const coords = _cleanMultiPolygonCoords(geometry.coordinates);
|
|
1384
|
+
return coords ? multiPolygon(coords).geometry : null;
|
|
1572
1385
|
}
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1386
|
+
return null;
|
|
1387
|
+
}
|
|
1388
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
1389
|
+
function _txContourCoords(cc, distance) {
|
|
1390
|
+
return cc.map(c => [c[0] + distance, c[1]]);
|
|
1391
|
+
}
|
|
1392
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
1393
|
+
function _txPolygonCoords(ccc, distance) {
|
|
1394
|
+
return ccc.map(cc => _txContourCoords(cc, distance));
|
|
1395
|
+
}
|
|
1396
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
1397
|
+
function _txMultiPolygonCoords(cccc, distance) {
|
|
1398
|
+
return cccc.map(ccc => _txPolygonCoords(ccc, distance));
|
|
1399
|
+
}
|
|
1400
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
1401
|
+
function _tx(geometry, distance) {
|
|
1402
|
+
if (geometry && getType(geometry) === 'Polygon') {
|
|
1403
|
+
const coords = _txPolygonCoords(geometry.coordinates, distance);
|
|
1404
|
+
return polygon(coords).geometry;
|
|
1405
|
+
} else if (geometry && getType(geometry) === 'MultiPolygon') {
|
|
1406
|
+
const coords = _txMultiPolygonCoords(geometry.coordinates, distance);
|
|
1407
|
+
return multiPolygon(coords).geometry;
|
|
1408
|
+
} else {
|
|
1409
|
+
return null;
|
|
1578
1410
|
}
|
|
1579
|
-
|
|
1411
|
+
}
|
|
1412
|
+
function _isPolygon(geometry) {
|
|
1413
|
+
return getType(geometry) === 'Polygon';
|
|
1414
|
+
}
|
|
1415
|
+
function _isMultiPolygon(geometry) {
|
|
1416
|
+
return getType(geometry) === 'MultiPolygon';
|
|
1580
1417
|
}
|
|
1581
1418
|
|
|
1582
|
-
//
|
|
1419
|
+
// deck.gl
|
|
1583
1420
|
// SPDX-License-Identifier: MIT
|
|
1584
1421
|
// Copyright (c) vis.gl contributors
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
debug: false,
|
|
1588
|
-
precision: 4,
|
|
1589
|
-
printTypes: false,
|
|
1590
|
-
printDegrees: false,
|
|
1591
|
-
printRowMajor: true,
|
|
1592
|
-
_cartographicRadians: false
|
|
1593
|
-
};
|
|
1594
|
-
// Configuration is truly global as of v3.6 to ensure single config even if multiple copies of math.gl
|
|
1595
|
-
// Multiple copies of config can be quite tricky to debug...
|
|
1596
|
-
globalThis.mathgl = globalThis.mathgl || {
|
|
1597
|
-
config: {
|
|
1598
|
-
...DEFAULT_CONFIG
|
|
1599
|
-
}
|
|
1600
|
-
};
|
|
1601
|
-
/**
|
|
1602
|
-
* Check if value is an "array"
|
|
1603
|
-
* Returns `true` if value is either an array or a typed array
|
|
1604
|
-
* Note: returns `false` for `ArrayBuffer` and `DataView` instances
|
|
1605
|
-
* @note isTypedArray and isNumericArray are often more useful in TypeScript
|
|
1606
|
-
*/
|
|
1607
|
-
function isArray(value) {
|
|
1608
|
-
return Array.isArray(value) || ArrayBuffer.isView(value) && !(value instanceof DataView);
|
|
1422
|
+
function joinPath(...args) {
|
|
1423
|
+
return args.map(part => part.endsWith('/') ? part.slice(0, -1) : part).join('/');
|
|
1609
1424
|
}
|
|
1610
|
-
function
|
|
1611
|
-
|
|
1612
|
-
return a.map((ai, i) => lerp(ai, b[i], t));
|
|
1613
|
-
}
|
|
1614
|
-
return t * b + (1 - t) * a;
|
|
1425
|
+
function buildV3Path(apiBaseUrl, version, endpoint, ...rest) {
|
|
1426
|
+
return joinPath(apiBaseUrl, version, endpoint, ...rest);
|
|
1615
1427
|
}
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1428
|
+
/** @internal Required by fetchMap(). */
|
|
1429
|
+
function buildPublicMapUrl({
|
|
1430
|
+
apiBaseUrl,
|
|
1431
|
+
cartoMapId
|
|
1432
|
+
}) {
|
|
1433
|
+
return buildV3Path(apiBaseUrl, 'v3', 'maps', 'public', cartoMapId);
|
|
1434
|
+
}
|
|
1435
|
+
/** @internal Required by fetchMap(). */
|
|
1436
|
+
function buildStatsUrl({
|
|
1437
|
+
attribute,
|
|
1438
|
+
apiBaseUrl,
|
|
1439
|
+
connectionName,
|
|
1440
|
+
source,
|
|
1441
|
+
type
|
|
1442
|
+
}) {
|
|
1443
|
+
if (type === 'query') {
|
|
1444
|
+
return buildV3Path(apiBaseUrl, 'v3', 'stats', connectionName, attribute);
|
|
1623
1445
|
}
|
|
1446
|
+
// type === 'table'
|
|
1447
|
+
return buildV3Path(apiBaseUrl, 'v3', 'stats', connectionName, source, attribute);
|
|
1448
|
+
}
|
|
1449
|
+
function buildSourceUrl({
|
|
1450
|
+
apiBaseUrl,
|
|
1451
|
+
connectionName,
|
|
1452
|
+
endpoint
|
|
1453
|
+
}) {
|
|
1454
|
+
return buildV3Path(apiBaseUrl, 'v3', 'maps', connectionName, endpoint);
|
|
1455
|
+
}
|
|
1456
|
+
function buildQueryUrl({
|
|
1457
|
+
apiBaseUrl,
|
|
1458
|
+
connectionName
|
|
1459
|
+
}) {
|
|
1460
|
+
return buildV3Path(apiBaseUrl, 'v3', 'sql', connectionName, 'query');
|
|
1624
1461
|
}
|
|
1625
1462
|
|
|
1626
|
-
//
|
|
1627
|
-
//
|
|
1628
|
-
|
|
1629
|
-
const PI_4 = PI / 4;
|
|
1630
|
-
const DEGREES_TO_RADIANS = PI / 180;
|
|
1631
|
-
const RADIANS_TO_DEGREES = 180 / PI;
|
|
1632
|
-
const TILE_SIZE = 512;
|
|
1463
|
+
// deck.gl
|
|
1464
|
+
// SPDX-License-Identifier: MIT
|
|
1465
|
+
// Copyright (c) vis.gl contributors
|
|
1633
1466
|
/**
|
|
1634
|
-
* Project [lng,lat] on sphere onto [x,y] on 512*512 Mercator Zoom 0 tile.
|
|
1635
|
-
* Performs the nonlinear part of the web mercator projection.
|
|
1636
|
-
* Remaining projection is done with 4x4 matrices which also handles
|
|
1637
|
-
* perspective.
|
|
1638
1467
|
*
|
|
1639
|
-
*
|
|
1640
|
-
*
|
|
1641
|
-
*
|
|
1468
|
+
* Custom error for reported errors in CARTO Maps API.
|
|
1469
|
+
* Provides useful debugging information in console and context for applications.
|
|
1470
|
+
*
|
|
1642
1471
|
*/
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1472
|
+
class CartoAPIError extends Error {
|
|
1473
|
+
constructor(error, errorContext, response, responseJson) {
|
|
1474
|
+
let responseString = 'Failed to connect';
|
|
1475
|
+
if (response) {
|
|
1476
|
+
responseString = 'Server returned: ';
|
|
1477
|
+
if (response.status === 400) {
|
|
1478
|
+
responseString += 'Bad request';
|
|
1479
|
+
} else if (response.status === 401 || response.status === 403) {
|
|
1480
|
+
responseString += 'Unauthorized access';
|
|
1481
|
+
} else if (response.status === 404) {
|
|
1482
|
+
responseString += 'Not found';
|
|
1483
|
+
} else {
|
|
1484
|
+
responseString += 'Error';
|
|
1485
|
+
}
|
|
1486
|
+
responseString += ` (${response.status}):`;
|
|
1487
|
+
}
|
|
1488
|
+
responseString += ` ${error.message || error}`;
|
|
1489
|
+
let message = `${errorContext.requestType} API request failed`;
|
|
1490
|
+
message += `\n${responseString}`;
|
|
1491
|
+
for (const key of Object.keys(errorContext)) {
|
|
1492
|
+
if (key === 'requestType') continue;
|
|
1493
|
+
message += `\n${formatErrorKey(key)}: ${errorContext[key]}`;
|
|
1494
|
+
}
|
|
1495
|
+
message += '\n';
|
|
1496
|
+
super(message);
|
|
1497
|
+
/** Source error from server */
|
|
1498
|
+
this.error = void 0;
|
|
1499
|
+
/** Context (API call & parameters) in which error occured */
|
|
1500
|
+
this.errorContext = void 0;
|
|
1501
|
+
/** Response from server */
|
|
1502
|
+
this.response = void 0;
|
|
1503
|
+
/** JSON Response from server */
|
|
1504
|
+
this.responseJson = void 0;
|
|
1505
|
+
this.name = 'CartoAPIError';
|
|
1506
|
+
this.response = response;
|
|
1507
|
+
this.responseJson = responseJson;
|
|
1508
|
+
this.error = error;
|
|
1509
|
+
this.errorContext = errorContext;
|
|
1510
|
+
}
|
|
1652
1511
|
}
|
|
1653
1512
|
/**
|
|
1654
|
-
*
|
|
1655
|
-
*
|
|
1656
|
-
* @param xy - array with [x,y] members
|
|
1657
|
-
* representing point on projected map plane
|
|
1658
|
-
* @return - array with [x,y] of point on sphere.
|
|
1659
|
-
* Has toArray method if you need a GeoJSON Array.
|
|
1660
|
-
* Per cartographic tradition, lat and lon are specified as degrees.
|
|
1513
|
+
* Converts camelCase to Camel Case
|
|
1661
1514
|
*/
|
|
1662
|
-
function
|
|
1663
|
-
|
|
1664
|
-
const lambda2 = x / TILE_SIZE * (2 * PI) - PI;
|
|
1665
|
-
const phi2 = 2 * (Math.atan(Math.exp(y / TILE_SIZE * (2 * PI) - PI)) - PI_4);
|
|
1666
|
-
return [lambda2 * RADIANS_TO_DEGREES, phi2 * RADIANS_TO_DEGREES];
|
|
1515
|
+
function formatErrorKey(key) {
|
|
1516
|
+
return key.replace(/([A-Z])/g, ' $1').replace(/^./, s => s.toUpperCase());
|
|
1667
1517
|
}
|
|
1668
1518
|
|
|
1669
|
-
const
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
LineString: transformLineString$1,
|
|
1673
|
-
MultiLineString: transformMultiLineString$1,
|
|
1674
|
-
Polygon: transformPolygon$1,
|
|
1675
|
-
MultiPolygon: transformMultiPolygon$1
|
|
1519
|
+
const DEFAULT_HEADERS = {
|
|
1520
|
+
Accept: 'application/json',
|
|
1521
|
+
'Content-Type': 'application/json'
|
|
1676
1522
|
};
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1523
|
+
const DEFAULT_REQUEST_CACHE = new Map();
|
|
1524
|
+
async function requestWithParameters({
|
|
1525
|
+
baseUrl,
|
|
1526
|
+
parameters = {},
|
|
1527
|
+
headers: customHeaders = {},
|
|
1528
|
+
errorContext,
|
|
1529
|
+
maxLengthURL = DEFAULT_MAX_LENGTH_URL,
|
|
1530
|
+
localCache
|
|
1531
|
+
}) {
|
|
1532
|
+
// Parameters added to all requests issued with `requestWithParameters()`.
|
|
1533
|
+
// These parameters override parameters already in the base URL, but not
|
|
1534
|
+
// user-provided parameters.
|
|
1535
|
+
parameters = _extends({
|
|
1536
|
+
v: V3_MINOR_VERSION,
|
|
1537
|
+
client: getClient()
|
|
1538
|
+
}, typeof deck !== 'undefined' && deck.VERSION && {
|
|
1539
|
+
deckglVersion: deck.VERSION
|
|
1540
|
+
}, parameters);
|
|
1541
|
+
baseUrl = excludeURLParameters(baseUrl, Object.keys(parameters));
|
|
1542
|
+
const key = createCacheKey(baseUrl, parameters, customHeaders);
|
|
1543
|
+
const {
|
|
1544
|
+
cache: REQUEST_CACHE,
|
|
1545
|
+
canReadCache,
|
|
1546
|
+
canStoreInCache
|
|
1547
|
+
} = getCacheSettings(localCache);
|
|
1548
|
+
if (canReadCache && REQUEST_CACHE.has(key)) {
|
|
1549
|
+
return REQUEST_CACHE.get(key);
|
|
1691
1550
|
}
|
|
1692
|
-
const
|
|
1693
|
-
const
|
|
1694
|
-
|
|
1695
|
-
|
|
1551
|
+
const url = createURLWithParameters(baseUrl, parameters);
|
|
1552
|
+
const headers = _extends({}, DEFAULT_HEADERS, customHeaders);
|
|
1553
|
+
/* global fetch */
|
|
1554
|
+
const fetchPromise = url.length > maxLengthURL ? fetch(baseUrl, {
|
|
1555
|
+
method: 'POST',
|
|
1556
|
+
body: JSON.stringify(parameters),
|
|
1557
|
+
headers
|
|
1558
|
+
}) : fetch(url, {
|
|
1559
|
+
headers
|
|
1560
|
+
});
|
|
1561
|
+
let response;
|
|
1562
|
+
let responseJson;
|
|
1563
|
+
const jsonPromise = fetchPromise.then(_response => {
|
|
1564
|
+
response = _response;
|
|
1565
|
+
return response.json();
|
|
1566
|
+
}).then(json => {
|
|
1567
|
+
responseJson = json;
|
|
1568
|
+
if (!response || !response.ok) {
|
|
1569
|
+
throw new Error(json.error);
|
|
1570
|
+
}
|
|
1571
|
+
return json;
|
|
1572
|
+
}).catch(error => {
|
|
1573
|
+
if (canStoreInCache) {
|
|
1574
|
+
REQUEST_CACHE.delete(key);
|
|
1575
|
+
}
|
|
1576
|
+
throw new CartoAPIError(error, errorContext, response, responseJson);
|
|
1696
1577
|
});
|
|
1578
|
+
if (canStoreInCache) {
|
|
1579
|
+
REQUEST_CACHE.set(key, jsonPromise);
|
|
1580
|
+
}
|
|
1581
|
+
return jsonPromise;
|
|
1697
1582
|
}
|
|
1698
|
-
function
|
|
1699
|
-
|
|
1700
|
-
const
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
}
|
|
1709
|
-
function transformLineString$1(line, bbox) {
|
|
1710
|
-
return getPoints$1(line, bbox);
|
|
1711
|
-
}
|
|
1712
|
-
function transformMultiLineString$1(multiLineString, bbox) {
|
|
1713
|
-
return multiLineString.map(lineString => transformLineString$1(lineString, bbox));
|
|
1714
|
-
}
|
|
1715
|
-
function transformPolygon$1(polygon, bbox) {
|
|
1716
|
-
return polygon.map(polygonRing => getPoints$1(polygonRing, bbox));
|
|
1717
|
-
}
|
|
1718
|
-
function transformMultiPolygon$1(multiPolygon, bbox) {
|
|
1719
|
-
return multiPolygon.map(polygon => transformPolygon$1(polygon, bbox));
|
|
1720
|
-
}
|
|
1721
|
-
function projectFlat(xyz) {
|
|
1722
|
-
return lngLatToWorld(xyz);
|
|
1583
|
+
function getCacheSettings(localCache) {
|
|
1584
|
+
var _localCache$cacheCont, _localCache$cacheCont2;
|
|
1585
|
+
const canReadCache = localCache != null && (_localCache$cacheCont = localCache.cacheControl) != null && _localCache$cacheCont.includes('no-cache') ? false : true;
|
|
1586
|
+
const canStoreInCache = localCache != null && (_localCache$cacheCont2 = localCache.cacheControl) != null && _localCache$cacheCont2.includes('no-store') ? false : true;
|
|
1587
|
+
const cache = (localCache == null ? void 0 : localCache.cache) || DEFAULT_REQUEST_CACHE;
|
|
1588
|
+
return {
|
|
1589
|
+
cache,
|
|
1590
|
+
canReadCache,
|
|
1591
|
+
canStoreInCache
|
|
1592
|
+
};
|
|
1723
1593
|
}
|
|
1724
|
-
function
|
|
1725
|
-
|
|
1594
|
+
function createCacheKey(baseUrl, parameters, headers) {
|
|
1595
|
+
const parameterEntries = Object.entries(parameters).sort(([a], [b]) => a > b ? 1 : -1);
|
|
1596
|
+
const headerEntries = Object.entries(headers).sort(([a], [b]) => a > b ? 1 : -1);
|
|
1597
|
+
return JSON.stringify({
|
|
1598
|
+
baseUrl,
|
|
1599
|
+
parameters: parameterEntries,
|
|
1600
|
+
headers: headerEntries
|
|
1601
|
+
});
|
|
1726
1602
|
}
|
|
1727
|
-
|
|
1728
|
-
const TRANSFORM_FN = {
|
|
1729
|
-
Point: transformPoint,
|
|
1730
|
-
MultiPoint: transformMultiPoint,
|
|
1731
|
-
LineString: transformLineString,
|
|
1732
|
-
MultiLineString: transformMultiLineString,
|
|
1733
|
-
Polygon: transformPolygon,
|
|
1734
|
-
MultiPolygon: transformMultiPolygon
|
|
1735
|
-
};
|
|
1736
1603
|
/**
|
|
1737
|
-
*
|
|
1738
|
-
*
|
|
1739
|
-
*
|
|
1740
|
-
* @param bbox - geojson bbox
|
|
1604
|
+
* Appends query string parameters to a URL. Existing URL parameters are kept,
|
|
1605
|
+
* unless there is a conflict, in which case the new parameters override
|
|
1606
|
+
* those already in the URL.
|
|
1741
1607
|
*/
|
|
1742
|
-
function
|
|
1743
|
-
const
|
|
1744
|
-
const
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1608
|
+
function createURLWithParameters(baseUrlString, parameters) {
|
|
1609
|
+
const baseUrl = new URL(baseUrlString);
|
|
1610
|
+
for (const [key, value] of Object.entries(parameters)) {
|
|
1611
|
+
if (isPureObject(value) || Array.isArray(value)) {
|
|
1612
|
+
baseUrl.searchParams.set(key, JSON.stringify(value));
|
|
1613
|
+
} else {
|
|
1614
|
+
baseUrl.searchParams.set(key, value.toString());
|
|
1615
|
+
}
|
|
1749
1616
|
}
|
|
1750
|
-
|
|
1751
|
-
const coordinates = transformFn(geometry.coordinates, projectedBbox);
|
|
1752
|
-
return _extends({}, geometry, {
|
|
1753
|
-
coordinates
|
|
1754
|
-
});
|
|
1755
|
-
}
|
|
1756
|
-
function transformPoint([pointX, pointY], [nw, se]) {
|
|
1757
|
-
const x = lerp(nw[0], se[0], pointX);
|
|
1758
|
-
const y = lerp(nw[1], se[1], pointY);
|
|
1759
|
-
return worldToLngLat([x, y]);
|
|
1760
|
-
}
|
|
1761
|
-
function getPoints(geometry, bbox) {
|
|
1762
|
-
return geometry.map(g => transformPoint(g, bbox));
|
|
1763
|
-
}
|
|
1764
|
-
function transformMultiPoint(multiPoint, bbox) {
|
|
1765
|
-
return getPoints(multiPoint, bbox);
|
|
1766
|
-
}
|
|
1767
|
-
function transformLineString(line, bbox) {
|
|
1768
|
-
return getPoints(line, bbox);
|
|
1769
|
-
}
|
|
1770
|
-
function transformMultiLineString(multiLineString, bbox) {
|
|
1771
|
-
return multiLineString.map(lineString => transformLineString(lineString, bbox));
|
|
1772
|
-
}
|
|
1773
|
-
function transformPolygon(polygon, bbox) {
|
|
1774
|
-
return polygon.map(polygonRing => getPoints(polygonRing, bbox));
|
|
1775
|
-
}
|
|
1776
|
-
function transformMultiPolygon(multiPolygon, bbox) {
|
|
1777
|
-
return multiPolygon.map(polygon => transformPolygon(polygon, bbox));
|
|
1617
|
+
return baseUrl.toString();
|
|
1778
1618
|
}
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
}) {
|
|
1788
|
-
const map = new Map();
|
|
1789
|
-
for (const tile of tiles) {
|
|
1790
|
-
// Discard if it's not a visible tile (only check false value, not undefined)
|
|
1791
|
-
// or tile has not data
|
|
1792
|
-
if (tile.isVisible === false || !tile.data) {
|
|
1793
|
-
continue;
|
|
1794
|
-
}
|
|
1795
|
-
const bbox = [tile.bbox.west, tile.bbox.south, tile.bbox.east, tile.bbox.north];
|
|
1796
|
-
const bboxToGeom = bboxPolygon(bbox);
|
|
1797
|
-
const tileIsFullyVisible = booleanWithin(bboxToGeom, spatialFilter);
|
|
1798
|
-
// Clip the geometry to intersect with the tile
|
|
1799
|
-
const spatialFilterFeature = {
|
|
1800
|
-
type: 'Feature',
|
|
1801
|
-
geometry: spatialFilter,
|
|
1802
|
-
properties: {}
|
|
1803
|
-
};
|
|
1804
|
-
const clippedGeometryToIntersect = intersect(featureCollection([bboxToGeom, spatialFilterFeature]));
|
|
1805
|
-
if (!clippedGeometryToIntersect) {
|
|
1806
|
-
continue;
|
|
1619
|
+
/**
|
|
1620
|
+
* Deletes query string parameters from a URL.
|
|
1621
|
+
*/
|
|
1622
|
+
function excludeURLParameters(baseUrlString, parameters) {
|
|
1623
|
+
const baseUrl = new URL(baseUrlString);
|
|
1624
|
+
for (const param of parameters) {
|
|
1625
|
+
if (baseUrl.searchParams.has(param)) {
|
|
1626
|
+
baseUrl.searchParams.delete(param);
|
|
1807
1627
|
}
|
|
1808
|
-
// We assume that MVT tileFormat uses local coordinates so we transform the geometry to intersect to tile coordinates [0..1],
|
|
1809
|
-
// while in the case of 'geojson' or binary, the geometries are already in WGS84
|
|
1810
|
-
const transformedGeometryToIntersect = tileFormat === TileFormat.MVT ? transformToTileCoords(clippedGeometryToIntersect.geometry, bbox) : clippedGeometryToIntersect.geometry;
|
|
1811
|
-
createIndicesForPoints(tile.data.points);
|
|
1812
|
-
calculateFeatures({
|
|
1813
|
-
map,
|
|
1814
|
-
tileIsFullyVisible,
|
|
1815
|
-
geometryIntersection: transformedGeometryToIntersect,
|
|
1816
|
-
data: tile.data.points,
|
|
1817
|
-
type: 'Point',
|
|
1818
|
-
bbox,
|
|
1819
|
-
tileFormat,
|
|
1820
|
-
uniqueIdProperty,
|
|
1821
|
-
options
|
|
1822
|
-
});
|
|
1823
|
-
calculateFeatures({
|
|
1824
|
-
map,
|
|
1825
|
-
tileIsFullyVisible,
|
|
1826
|
-
geometryIntersection: transformedGeometryToIntersect,
|
|
1827
|
-
data: tile.data.lines,
|
|
1828
|
-
type: 'LineString',
|
|
1829
|
-
bbox,
|
|
1830
|
-
tileFormat,
|
|
1831
|
-
uniqueIdProperty,
|
|
1832
|
-
options
|
|
1833
|
-
});
|
|
1834
|
-
calculateFeatures({
|
|
1835
|
-
map,
|
|
1836
|
-
tileIsFullyVisible,
|
|
1837
|
-
geometryIntersection: transformedGeometryToIntersect,
|
|
1838
|
-
data: tile.data.polygons,
|
|
1839
|
-
type: 'Polygon',
|
|
1840
|
-
bbox,
|
|
1841
|
-
tileFormat,
|
|
1842
|
-
uniqueIdProperty,
|
|
1843
|
-
options
|
|
1844
|
-
});
|
|
1845
1628
|
}
|
|
1846
|
-
return
|
|
1629
|
+
return baseUrl.toString();
|
|
1847
1630
|
}
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
}
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
}
|
|
1874
|
-
// If intersection is required, check before proceeding
|
|
1875
|
-
if (geometry && geometryIntersection && !intersects(geometry, geometryIntersection)) {
|
|
1876
|
-
return;
|
|
1631
|
+
|
|
1632
|
+
const _excluded$1 = ["accessToken", "connectionName", "cache"];
|
|
1633
|
+
const SOURCE_DEFAULTS = {
|
|
1634
|
+
apiBaseUrl: DEFAULT_API_BASE_URL,
|
|
1635
|
+
clientId: getClient(),
|
|
1636
|
+
format: 'tilejson',
|
|
1637
|
+
headers: {},
|
|
1638
|
+
maxLengthURL: DEFAULT_MAX_LENGTH_URL
|
|
1639
|
+
};
|
|
1640
|
+
async function baseSource(endpoint, options, urlParameters) {
|
|
1641
|
+
const {
|
|
1642
|
+
accessToken,
|
|
1643
|
+
connectionName,
|
|
1644
|
+
cache
|
|
1645
|
+
} = options,
|
|
1646
|
+
optionalOptions = _objectWithoutPropertiesLoose(options, _excluded$1);
|
|
1647
|
+
const mergedOptions = _extends({}, SOURCE_DEFAULTS, {
|
|
1648
|
+
accessToken,
|
|
1649
|
+
connectionName,
|
|
1650
|
+
endpoint
|
|
1651
|
+
});
|
|
1652
|
+
for (const key in optionalOptions) {
|
|
1653
|
+
if (optionalOptions[key]) {
|
|
1654
|
+
mergedOptions[key] = optionalOptions[key];
|
|
1655
|
+
}
|
|
1877
1656
|
}
|
|
1878
|
-
const
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1657
|
+
const baseUrl = buildSourceUrl(mergedOptions);
|
|
1658
|
+
const {
|
|
1659
|
+
clientId,
|
|
1660
|
+
maxLengthURL,
|
|
1661
|
+
format,
|
|
1662
|
+
localCache
|
|
1663
|
+
} = mergedOptions;
|
|
1664
|
+
const headers = _extends({
|
|
1665
|
+
Authorization: `Bearer ${options.accessToken}`
|
|
1666
|
+
}, options.headers);
|
|
1667
|
+
const parameters = _extends({
|
|
1668
|
+
client: clientId
|
|
1669
|
+
}, urlParameters);
|
|
1670
|
+
const errorContext = {
|
|
1671
|
+
requestType: 'Map instantiation',
|
|
1672
|
+
connection: options.connectionName,
|
|
1673
|
+
type: endpoint,
|
|
1674
|
+
source: JSON.stringify(parameters, undefined, 2)
|
|
1675
|
+
};
|
|
1676
|
+
const mapInstantiation = await requestWithParameters({
|
|
1677
|
+
baseUrl,
|
|
1678
|
+
parameters,
|
|
1679
|
+
headers,
|
|
1680
|
+
errorContext,
|
|
1681
|
+
maxLengthURL,
|
|
1682
|
+
localCache
|
|
1683
|
+
});
|
|
1684
|
+
const dataUrl = mapInstantiation[format].url[0];
|
|
1685
|
+
if (cache) {
|
|
1686
|
+
cache.value = parseInt(new URL(dataUrl).searchParams.get('cache') || '', 10);
|
|
1882
1687
|
}
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
tileFormat,
|
|
1892
|
-
uniqueIdProperty,
|
|
1893
|
-
options
|
|
1894
|
-
}) {
|
|
1895
|
-
const indices = getIndices(data);
|
|
1896
|
-
const storeGeometry = (options == null ? void 0 : options.storeGeometry) || false;
|
|
1897
|
-
for (let i = 0; i < indices.length - 1; i++) {
|
|
1898
|
-
const startIndex = indices[i];
|
|
1899
|
-
const endIndex = indices[i + 1];
|
|
1900
|
-
processTileFeatureProperties({
|
|
1901
|
-
map,
|
|
1902
|
-
data,
|
|
1903
|
-
startIndex,
|
|
1904
|
-
endIndex,
|
|
1905
|
-
type,
|
|
1906
|
-
bbox,
|
|
1907
|
-
tileFormat,
|
|
1908
|
-
uniqueIdProperty,
|
|
1909
|
-
storeGeometry,
|
|
1910
|
-
geometryIntersection
|
|
1688
|
+
errorContext.requestType = 'Map data';
|
|
1689
|
+
if (format === 'tilejson') {
|
|
1690
|
+
const json = await requestWithParameters({
|
|
1691
|
+
baseUrl: dataUrl,
|
|
1692
|
+
headers,
|
|
1693
|
+
errorContext,
|
|
1694
|
+
maxLengthURL,
|
|
1695
|
+
localCache
|
|
1911
1696
|
});
|
|
1697
|
+
if (accessToken) {
|
|
1698
|
+
json.accessToken = accessToken;
|
|
1699
|
+
}
|
|
1700
|
+
return json;
|
|
1912
1701
|
}
|
|
1702
|
+
return await requestWithParameters({
|
|
1703
|
+
baseUrl: dataUrl,
|
|
1704
|
+
headers,
|
|
1705
|
+
errorContext,
|
|
1706
|
+
maxLengthURL,
|
|
1707
|
+
localCache
|
|
1708
|
+
});
|
|
1913
1709
|
}
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
indices = data.pointIndices;
|
|
1920
|
-
break;
|
|
1921
|
-
case 'LineString':
|
|
1922
|
-
indices = data.pathIndices;
|
|
1923
|
-
break;
|
|
1924
|
-
case 'Polygon':
|
|
1925
|
-
indices = data.primitivePolygonIndices;
|
|
1926
|
-
break;
|
|
1927
|
-
default:
|
|
1928
|
-
throw new Error(`Unexpected type, "${data.type}"`);
|
|
1929
|
-
}
|
|
1930
|
-
return indices.value;
|
|
1931
|
-
}
|
|
1932
|
-
function getFeatureId(data, startIndex) {
|
|
1933
|
-
return data.featureIds.value[startIndex];
|
|
1934
|
-
}
|
|
1935
|
-
function getPropertiesFromTile(data, startIndex) {
|
|
1936
|
-
var _fields$featureId;
|
|
1937
|
-
const featureId = getFeatureId(data, startIndex);
|
|
1710
|
+
|
|
1711
|
+
// deck.gl
|
|
1712
|
+
// SPDX-License-Identifier: MIT
|
|
1713
|
+
// Copyright (c) vis.gl contributors
|
|
1714
|
+
const boundaryQuerySource = async function boundaryQuerySource(options) {
|
|
1938
1715
|
const {
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1716
|
+
columns,
|
|
1717
|
+
filters,
|
|
1718
|
+
tilesetTableName,
|
|
1719
|
+
propertiesSqlQuery,
|
|
1720
|
+
queryParameters
|
|
1721
|
+
} = options;
|
|
1722
|
+
const urlParameters = {
|
|
1723
|
+
tilesetTableName,
|
|
1724
|
+
propertiesSqlQuery
|
|
1947
1725
|
};
|
|
1948
|
-
|
|
1949
|
-
|
|
1726
|
+
if (columns) {
|
|
1727
|
+
urlParameters.columns = columns.join(',');
|
|
1950
1728
|
}
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1729
|
+
if (filters) {
|
|
1730
|
+
urlParameters.filters = filters;
|
|
1731
|
+
}
|
|
1732
|
+
if (queryParameters) {
|
|
1733
|
+
urlParameters.queryParameters = queryParameters;
|
|
1734
|
+
}
|
|
1735
|
+
return baseSource('boundary', options, urlParameters);
|
|
1736
|
+
};
|
|
1737
|
+
|
|
1738
|
+
// deck.gl
|
|
1739
|
+
// SPDX-License-Identifier: MIT
|
|
1740
|
+
// Copyright (c) vis.gl contributors
|
|
1741
|
+
const boundaryTableSource = async function boundaryTableSource(options) {
|
|
1954
1742
|
const {
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
}
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1743
|
+
filters,
|
|
1744
|
+
tilesetTableName,
|
|
1745
|
+
columns,
|
|
1746
|
+
propertiesTableName
|
|
1747
|
+
} = options;
|
|
1748
|
+
const urlParameters = {
|
|
1749
|
+
tilesetTableName,
|
|
1750
|
+
propertiesTableName
|
|
1751
|
+
};
|
|
1752
|
+
if (columns) {
|
|
1753
|
+
urlParameters.columns = columns.join(',');
|
|
1963
1754
|
}
|
|
1964
|
-
if (
|
|
1965
|
-
|
|
1755
|
+
if (filters) {
|
|
1756
|
+
urlParameters.filters = filters;
|
|
1966
1757
|
}
|
|
1967
|
-
|
|
1968
|
-
|
|
1758
|
+
return baseSource('boundary', options, urlParameters);
|
|
1759
|
+
};
|
|
1760
|
+
|
|
1761
|
+
const DEFAULT_TILE_SIZE = 512;
|
|
1762
|
+
const QUADBIN_ZOOM_MAX_OFFSET = 4;
|
|
1763
|
+
function getSpatialFiltersResolution(source, viewState) {
|
|
1764
|
+
var _source$dataResolutio, _source$aggregationRe;
|
|
1765
|
+
const dataResolution = (_source$dataResolutio = source.dataResolution) != null ? _source$dataResolutio : Number.MAX_VALUE;
|
|
1766
|
+
const aggregationResLevel = (_source$aggregationRe = source.aggregationResLevel) != null ? _source$aggregationRe : source.spatialDataType === 'h3' ? DEFAULT_AGGREGATION_RES_LEVEL_H3 : DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN;
|
|
1767
|
+
const aggregationResLevelOffset = Math.max(0, Math.floor(aggregationResLevel));
|
|
1768
|
+
const currentZoomInt = Math.ceil(viewState.zoom);
|
|
1769
|
+
if (source.spatialDataType === 'h3') {
|
|
1770
|
+
var _maxH3SpatialFiltersR, _maxH3SpatialFiltersR2;
|
|
1771
|
+
const tileSize = DEFAULT_TILE_SIZE;
|
|
1772
|
+
const maxResolutionForZoom = (_maxH3SpatialFiltersR = (_maxH3SpatialFiltersR2 = maxH3SpatialFiltersResolutions.find(([zoom]) => zoom === currentZoomInt)) == null ? void 0 : _maxH3SpatialFiltersR2[1]) != null ? _maxH3SpatialFiltersR : Math.max(0, currentZoomInt - 3);
|
|
1773
|
+
const maxSpatialFiltersResolution = maxResolutionForZoom ? Math.min(dataResolution, maxResolutionForZoom) : dataResolution;
|
|
1774
|
+
const hexagonResolution = _getHexagonResolution(viewState, tileSize) + aggregationResLevelOffset;
|
|
1775
|
+
return Math.min(hexagonResolution, maxSpatialFiltersResolution);
|
|
1776
|
+
}
|
|
1777
|
+
if (source.spatialDataType === 'quadbin') {
|
|
1778
|
+
const maxResolutionForZoom = currentZoomInt + QUADBIN_ZOOM_MAX_OFFSET;
|
|
1779
|
+
const maxSpatialFiltersResolution = Math.min(dataResolution, maxResolutionForZoom);
|
|
1780
|
+
const quadsResolution = Math.floor(viewState.zoom) + aggregationResLevelOffset;
|
|
1781
|
+
return Math.min(quadsResolution, maxSpatialFiltersResolution);
|
|
1782
|
+
}
|
|
1783
|
+
return undefined;
|
|
1969
1784
|
}
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1785
|
+
const maxH3SpatialFiltersResolutions = [[20, 14], [19, 13], [18, 12], [17, 11], [16, 10], [15, 9], [14, 8], [13, 7], [12, 7], [11, 7], [10, 6], [9, 6], [8, 5], [7, 4], [6, 4], [5, 3], [4, 2], [3, 1], [2, 1], [1, 0]];
|
|
1786
|
+
// stolen from https://github.com/visgl/deck.gl/blob/master/modules/carto/src/layers/h3-tileset-2d.ts
|
|
1787
|
+
// Relative scale factor (0 = no biasing, 2 = a few hexagons cover view)
|
|
1788
|
+
const BIAS = 2;
|
|
1789
|
+
/**
|
|
1790
|
+
* Resolution conversion function. Takes a WebMercatorViewport and returns
|
|
1791
|
+
* a H3 resolution such that the screen space size of the hexagons is
|
|
1792
|
+
* "similar" to the given tileSize on screen. Intended for use with deck.gl.
|
|
1793
|
+
* @internal
|
|
1794
|
+
*/
|
|
1795
|
+
function _getHexagonResolution(viewport, tileSize) {
|
|
1796
|
+
// Difference in given tile size compared to deck's internal 512px tile size,
|
|
1797
|
+
// expressed as an offset to the viewport zoom.
|
|
1798
|
+
const zoomOffset = Math.log2(tileSize / DEFAULT_TILE_SIZE);
|
|
1799
|
+
const hexagonScaleFactor = 2 / 3 * (viewport.zoom - zoomOffset);
|
|
1800
|
+
const latitudeScaleFactor = Math.log(1 / Math.cos(Math.PI * viewport.latitude / 180));
|
|
1801
|
+
// Clip and bias
|
|
1802
|
+
return Math.max(0, Math.floor(hexagonScaleFactor + latitudeScaleFactor - BIAS));
|
|
1976
1803
|
}
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
coordinates
|
|
1988
|
-
};
|
|
1989
|
-
case 'Point':
|
|
1990
|
-
return {
|
|
1991
|
-
type: 'Point',
|
|
1992
|
-
coordinates: coordinates[0]
|
|
1993
|
-
};
|
|
1994
|
-
default:
|
|
1995
|
-
throw new Error('Invalid geometry type');
|
|
1804
|
+
|
|
1805
|
+
/**
|
|
1806
|
+
* Source for Widget API requests on a data source defined by a SQL query.
|
|
1807
|
+
*
|
|
1808
|
+
* Abstract class. Use {@link WidgetQuerySource} or {@link WidgetTableSource}.
|
|
1809
|
+
*/
|
|
1810
|
+
class WidgetSource {
|
|
1811
|
+
constructor(props) {
|
|
1812
|
+
this.props = void 0;
|
|
1813
|
+
this.props = _extends({}, WidgetSource.defaultProps, props);
|
|
1996
1814
|
}
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
1815
|
+
_getModelSource(filters, filterOwner) {
|
|
1816
|
+
const props = this.props;
|
|
1817
|
+
return {
|
|
1818
|
+
apiVersion: props.apiVersion,
|
|
1819
|
+
apiBaseUrl: props.apiBaseUrl,
|
|
1820
|
+
clientId: props.clientId,
|
|
1821
|
+
accessToken: props.accessToken,
|
|
1822
|
+
connectionName: props.connectionName,
|
|
1823
|
+
filters: getApplicableFilters(filterOwner, filters || props.filters),
|
|
1824
|
+
filtersLogicalOperator: props.filtersLogicalOperator,
|
|
1825
|
+
spatialDataType: props.spatialDataType,
|
|
1826
|
+
spatialDataColumn: props.spatialDataColumn,
|
|
1827
|
+
dataResolution: props.dataResolution
|
|
1828
|
+
};
|
|
1829
|
+
}
|
|
1830
|
+
_getSpatialFiltersResolution(source, spatialFilter, referenceViewState) {
|
|
1831
|
+
// spatialFiltersResolution applies only to spatial index sources.
|
|
1832
|
+
if (!spatialFilter || source.spatialDataType === 'geo') {
|
|
1833
|
+
return;
|
|
1834
|
+
}
|
|
1835
|
+
if (!referenceViewState) {
|
|
1836
|
+
throw new Error('Missing required option, "spatialIndexReferenceViewState".');
|
|
1837
|
+
}
|
|
1838
|
+
return getSpatialFiltersResolution(source, referenceViewState);
|
|
2002
1839
|
}
|
|
2003
|
-
return ringCoordinates;
|
|
2004
1840
|
}
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
1841
|
+
WidgetSource.defaultProps = {
|
|
1842
|
+
apiVersion: ApiVersion.V3,
|
|
1843
|
+
apiBaseUrl: DEFAULT_API_BASE_URL,
|
|
1844
|
+
clientId: getClient(),
|
|
1845
|
+
filters: {},
|
|
1846
|
+
filtersLogicalOperator: 'and'
|
|
1847
|
+
};
|
|
1848
|
+
|
|
1849
|
+
/**
|
|
1850
|
+
* Return more descriptive error from API
|
|
1851
|
+
* @privateRemarks Source: @carto/react-api
|
|
1852
|
+
*/
|
|
1853
|
+
function dealWithApiError({
|
|
1854
|
+
response,
|
|
1855
|
+
data
|
|
2015
1856
|
}) {
|
|
2016
|
-
|
|
2017
|
-
|
|
1857
|
+
var _data$error, _data$error2;
|
|
1858
|
+
if (data.error === 'Column not found') {
|
|
1859
|
+
throw new InvalidColumnError(`${data.error} ${data.column_name}`);
|
|
2018
1860
|
}
|
|
2019
|
-
if (
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
} else {
|
|
2030
|
-
addIntersectedFeaturesInTile({
|
|
2031
|
-
map,
|
|
2032
|
-
data,
|
|
2033
|
-
geometryIntersection,
|
|
2034
|
-
type,
|
|
2035
|
-
bbox,
|
|
2036
|
-
tileFormat,
|
|
2037
|
-
uniqueIdProperty,
|
|
2038
|
-
options
|
|
2039
|
-
});
|
|
1861
|
+
if (typeof data.error === 'string' && (_data$error = data.error) != null && _data$error.includes('Missing columns')) {
|
|
1862
|
+
throw new InvalidColumnError(data.error);
|
|
1863
|
+
}
|
|
1864
|
+
switch (response.status) {
|
|
1865
|
+
case 401:
|
|
1866
|
+
throw new Error('Unauthorized access. Invalid credentials');
|
|
1867
|
+
case 403:
|
|
1868
|
+
throw new Error('Forbidden access to the requested data');
|
|
1869
|
+
default:
|
|
1870
|
+
throw new Error(data && data.error && typeof data.error === 'string' ? data.error : JSON.stringify((data == null ? void 0 : data.hint) || ((_data$error2 = data.error) == null ? void 0 : _data$error2[0])));
|
|
2040
1871
|
}
|
|
2041
1872
|
}
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
tileFormat,
|
|
2048
|
-
uniqueIdProperty,
|
|
2049
|
-
options
|
|
1873
|
+
/** @privateRemarks Source: @carto/react-api */
|
|
1874
|
+
async function makeCall({
|
|
1875
|
+
url,
|
|
1876
|
+
accessToken,
|
|
1877
|
+
opts
|
|
2050
1878
|
}) {
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
1879
|
+
let response;
|
|
1880
|
+
let data;
|
|
1881
|
+
const isPost = (opts == null ? void 0 : opts.method) === 'POST';
|
|
1882
|
+
try {
|
|
1883
|
+
var _opts$abortController;
|
|
1884
|
+
response = await fetch(url.toString(), _extends({
|
|
1885
|
+
headers: _extends({
|
|
1886
|
+
Authorization: `Bearer ${accessToken}`
|
|
1887
|
+
}, isPost && {
|
|
1888
|
+
'Content-Type': 'application/json'
|
|
1889
|
+
}, opts.headers)
|
|
1890
|
+
}, isPost && {
|
|
1891
|
+
method: opts == null ? void 0 : opts.method,
|
|
1892
|
+
body: opts == null ? void 0 : opts.body
|
|
1893
|
+
}, {
|
|
1894
|
+
signal: opts == null || (_opts$abortController = opts.abortController) == null ? void 0 : _opts$abortController.signal
|
|
1895
|
+
}, opts == null ? void 0 : opts.otherOptions));
|
|
1896
|
+
data = await response.json();
|
|
1897
|
+
} catch (error) {
|
|
1898
|
+
if (error.name === 'AbortError') throw error;
|
|
1899
|
+
throw new Error(`Failed request: ${error}`);
|
|
1900
|
+
}
|
|
1901
|
+
if (!response.ok) {
|
|
1902
|
+
dealWithApiError({
|
|
1903
|
+
response,
|
|
1904
|
+
data
|
|
2066
1905
|
});
|
|
2067
1906
|
}
|
|
2068
|
-
|
|
2069
|
-
function createIndicesForPoints(data) {
|
|
2070
|
-
const featureIds = data.featureIds.value;
|
|
2071
|
-
const lastFeatureId = featureIds[featureIds.length - 1];
|
|
2072
|
-
const PointIndicesArray = featureIds.constructor;
|
|
2073
|
-
const pointIndices = {
|
|
2074
|
-
value: new PointIndicesArray(featureIds.length + 1),
|
|
2075
|
-
size: 1
|
|
2076
|
-
};
|
|
2077
|
-
pointIndices.value.set(featureIds);
|
|
2078
|
-
pointIndices.value.set([lastFeatureId + 1], featureIds.length);
|
|
2079
|
-
// @ts-expect-error Missing or changed types?
|
|
2080
|
-
data.pointIndices = pointIndices;
|
|
1907
|
+
return data;
|
|
2081
1908
|
}
|
|
2082
1909
|
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
1910
|
+
/** @privateRemarks Source: @carto/react-api */
|
|
1911
|
+
const AVAILABLE_MODELS = ['category', 'histogram', 'formula', 'pick', 'timeseries', 'range', 'scatterplot', 'table'];
|
|
1912
|
+
const {
|
|
1913
|
+
V3
|
|
1914
|
+
} = ApiVersion;
|
|
1915
|
+
const REQUEST_GET_MAX_URL_LENGTH = 2048;
|
|
1916
|
+
/**
|
|
1917
|
+
* Execute a SQL model request.
|
|
1918
|
+
* @privateRemarks Source: @carto/react-api
|
|
1919
|
+
*/
|
|
1920
|
+
function executeModel(props) {
|
|
1921
|
+
assert(props.source, 'executeModel: missing source');
|
|
1922
|
+
assert(props.model, 'executeModel: missing model');
|
|
1923
|
+
assert(props.params, 'executeModel: missing params');
|
|
1924
|
+
assert(AVAILABLE_MODELS.includes(props.model), `executeModel: model provided isn't valid. Available models: ${AVAILABLE_MODELS.join(', ')}`);
|
|
1925
|
+
const {
|
|
1926
|
+
model,
|
|
1927
|
+
source,
|
|
1928
|
+
params,
|
|
1929
|
+
opts
|
|
1930
|
+
} = props;
|
|
1931
|
+
const {
|
|
1932
|
+
type,
|
|
1933
|
+
apiVersion,
|
|
1934
|
+
apiBaseUrl,
|
|
1935
|
+
accessToken,
|
|
1936
|
+
connectionName,
|
|
1937
|
+
clientId
|
|
1938
|
+
} = source;
|
|
1939
|
+
assert(apiBaseUrl, 'executeModel: missing apiBaseUrl');
|
|
1940
|
+
assert(accessToken, 'executeModel: missing accessToken');
|
|
1941
|
+
assert(apiVersion === V3, 'executeModel: SQL Model API requires CARTO 3+');
|
|
1942
|
+
assert(type !== 'tileset', 'executeModel: Tilesets not supported');
|
|
1943
|
+
let url = `${apiBaseUrl}/v3/sql/${connectionName}/model/${model}`;
|
|
1944
|
+
const {
|
|
1945
|
+
data,
|
|
1946
|
+
filters,
|
|
1947
|
+
filtersLogicalOperator = 'and',
|
|
1948
|
+
spatialDataType = 'geo',
|
|
1949
|
+
spatialFiltersMode = 'intersects',
|
|
1950
|
+
spatialFiltersResolution = 0
|
|
1951
|
+
} = source;
|
|
1952
|
+
const queryParams = {
|
|
1953
|
+
type,
|
|
1954
|
+
client: clientId,
|
|
1955
|
+
source: data,
|
|
1956
|
+
params,
|
|
1957
|
+
queryParameters: source.queryParameters || '',
|
|
1958
|
+
filters,
|
|
1959
|
+
filtersLogicalOperator
|
|
1960
|
+
};
|
|
1961
|
+
const spatialDataColumn = source.spatialDataColumn || DEFAULT_GEO_COLUMN;
|
|
1962
|
+
// Picking Model API requires 'spatialDataColumn'.
|
|
1963
|
+
if (model === 'pick') {
|
|
1964
|
+
queryParams.spatialDataColumn = spatialDataColumn;
|
|
2095
1965
|
}
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
1966
|
+
// API supports multiple filters, we apply it only to spatialDataColumn
|
|
1967
|
+
const spatialFilters = source.spatialFilter ? {
|
|
1968
|
+
[spatialDataColumn]: source.spatialFilter
|
|
1969
|
+
} : undefined;
|
|
1970
|
+
if (spatialFilters) {
|
|
1971
|
+
queryParams.spatialFilters = spatialFilters;
|
|
1972
|
+
queryParams.spatialDataColumn = spatialDataColumn;
|
|
1973
|
+
queryParams.spatialDataType = spatialDataType;
|
|
2099
1974
|
}
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
if (tile.isVisible === false || !tile.data) {
|
|
2104
|
-
continue;
|
|
1975
|
+
if (spatialDataType !== 'geo') {
|
|
1976
|
+
if (spatialFiltersResolution > 0) {
|
|
1977
|
+
queryParams.spatialFiltersResolution = spatialFiltersResolution;
|
|
2105
1978
|
}
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
1979
|
+
queryParams.spatialFiltersMode = spatialFiltersMode;
|
|
1980
|
+
}
|
|
1981
|
+
const urlWithSearchParams = url + '?' + objectToURLSearchParams(queryParams).toString();
|
|
1982
|
+
const isGet = urlWithSearchParams.length <= REQUEST_GET_MAX_URL_LENGTH;
|
|
1983
|
+
if (isGet) {
|
|
1984
|
+
url = urlWithSearchParams;
|
|
1985
|
+
}
|
|
1986
|
+
return makeCall({
|
|
1987
|
+
url,
|
|
1988
|
+
accessToken: source.accessToken,
|
|
1989
|
+
opts: _extends({}, opts, {
|
|
1990
|
+
method: isGet ? 'GET' : 'POST'
|
|
1991
|
+
}, !isGet && {
|
|
1992
|
+
body: JSON.stringify(queryParams)
|
|
1993
|
+
})
|
|
1994
|
+
});
|
|
1995
|
+
}
|
|
1996
|
+
function objectToURLSearchParams(object) {
|
|
1997
|
+
const params = new URLSearchParams();
|
|
1998
|
+
for (const key in object) {
|
|
1999
|
+
if (isPureObject(object[key])) {
|
|
2000
|
+
params.append(key, JSON.stringify(object[key]));
|
|
2001
|
+
} else if (Array.isArray(object[key])) {
|
|
2002
|
+
params.append(key, JSON.stringify(object[key]));
|
|
2003
|
+
} else if (object[key] === null) {
|
|
2004
|
+
params.append(key, 'null');
|
|
2005
|
+
} else if (object[key] !== undefined) {
|
|
2006
|
+
params.append(key, String(object[key]));
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
return params;
|
|
2010
|
+
}
|
|
2011
|
+
|
|
2012
|
+
const _excluded = ["filters", "filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
|
|
2013
|
+
_excluded2 = ["filters", "filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
|
|
2014
|
+
_excluded3 = ["filters", "filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController", "operationExp"],
|
|
2015
|
+
_excluded4 = ["filters", "filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
|
|
2016
|
+
_excluded5 = ["filters", "filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
|
|
2017
|
+
_excluded6 = ["filters", "filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
|
|
2018
|
+
_excluded7 = ["filters", "filterOwner", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState", "abortController"],
|
|
2019
|
+
_excluded8 = ["filters", "filterOwner", "abortController", "spatialFilter", "spatialFiltersMode", "spatialIndexReferenceViewState"];
|
|
2020
|
+
/**
|
|
2021
|
+
* Source for Widget API requests.
|
|
2022
|
+
*
|
|
2023
|
+
* Abstract class. Use {@link WidgetQuerySource} or {@link WidgetTableSource}.
|
|
2024
|
+
*/
|
|
2025
|
+
class WidgetRemoteSource extends WidgetSource {
|
|
2026
|
+
constructor(...args) {
|
|
2027
|
+
super(...args);
|
|
2028
|
+
this._headers = {};
|
|
2113
2029
|
}
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
var _tiles$find;
|
|
2118
|
-
const data = (_tiles$find = tiles.find(tile => {
|
|
2119
|
-
var _tile$data;
|
|
2120
|
-
return (_tile$data = tile.data) == null ? void 0 : _tile$data.length;
|
|
2121
|
-
})) == null ? void 0 : _tiles$find.data;
|
|
2122
|
-
if (!data) {
|
|
2123
|
-
return;
|
|
2030
|
+
/** Assigns HTTP headers to be included on API requests from this source. */
|
|
2031
|
+
setRequestHeaders(headers) {
|
|
2032
|
+
this._headers = headers;
|
|
2124
2033
|
}
|
|
2125
|
-
|
|
2126
|
-
|
|
2034
|
+
async getCategories(options) {
|
|
2035
|
+
const {
|
|
2036
|
+
filters = this.props.filters,
|
|
2037
|
+
filterOwner,
|
|
2038
|
+
spatialFilter,
|
|
2039
|
+
spatialFiltersMode,
|
|
2040
|
+
spatialIndexReferenceViewState,
|
|
2041
|
+
abortController
|
|
2042
|
+
} = options,
|
|
2043
|
+
params = _objectWithoutPropertiesLoose(options, _excluded);
|
|
2044
|
+
const {
|
|
2045
|
+
column,
|
|
2046
|
+
operation,
|
|
2047
|
+
operationColumn
|
|
2048
|
+
} = params;
|
|
2049
|
+
const source = this.getModelSource(filters, filterOwner);
|
|
2050
|
+
const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
2051
|
+
return executeModel({
|
|
2052
|
+
model: 'category',
|
|
2053
|
+
source: _extends({}, source, {
|
|
2054
|
+
spatialFiltersResolution,
|
|
2055
|
+
spatialFiltersMode,
|
|
2056
|
+
spatialFilter
|
|
2057
|
+
}),
|
|
2058
|
+
params: {
|
|
2059
|
+
column,
|
|
2060
|
+
operation,
|
|
2061
|
+
operationColumn: operationColumn || column
|
|
2062
|
+
},
|
|
2063
|
+
opts: {
|
|
2064
|
+
abortController,
|
|
2065
|
+
headers: this._headers
|
|
2066
|
+
}
|
|
2067
|
+
}).then(res => normalizeObjectKeys(res.rows));
|
|
2127
2068
|
}
|
|
2128
|
-
|
|
2129
|
-
|
|
2069
|
+
async getFeatures(options) {
|
|
2070
|
+
const {
|
|
2071
|
+
filters = this.props.filters,
|
|
2072
|
+
filterOwner,
|
|
2073
|
+
spatialFilter,
|
|
2074
|
+
spatialFiltersMode,
|
|
2075
|
+
spatialIndexReferenceViewState,
|
|
2076
|
+
abortController
|
|
2077
|
+
} = options,
|
|
2078
|
+
params = _objectWithoutPropertiesLoose(options, _excluded2);
|
|
2079
|
+
const {
|
|
2080
|
+
columns,
|
|
2081
|
+
dataType,
|
|
2082
|
+
featureIds,
|
|
2083
|
+
z,
|
|
2084
|
+
limit,
|
|
2085
|
+
tileResolution
|
|
2086
|
+
} = params;
|
|
2087
|
+
const source = this.getModelSource(filters, filterOwner);
|
|
2088
|
+
const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
2089
|
+
return executeModel({
|
|
2090
|
+
model: 'pick',
|
|
2091
|
+
source: _extends({}, source, {
|
|
2092
|
+
spatialFiltersResolution,
|
|
2093
|
+
spatialFiltersMode,
|
|
2094
|
+
spatialFilter
|
|
2095
|
+
}),
|
|
2096
|
+
params: {
|
|
2097
|
+
columns,
|
|
2098
|
+
dataType,
|
|
2099
|
+
featureIds,
|
|
2100
|
+
z,
|
|
2101
|
+
limit: limit || 1000,
|
|
2102
|
+
tileResolution: tileResolution || DEFAULT_TILE_RESOLUTION
|
|
2103
|
+
},
|
|
2104
|
+
opts: {
|
|
2105
|
+
abortController,
|
|
2106
|
+
headers: this._headers
|
|
2107
|
+
}
|
|
2108
|
+
// Avoid `normalizeObjectKeys()`, which changes column names.
|
|
2109
|
+
}).then(({
|
|
2110
|
+
rows
|
|
2111
|
+
}) => ({
|
|
2112
|
+
rows
|
|
2113
|
+
}));
|
|
2130
2114
|
}
|
|
2131
|
-
|
|
2132
|
-
const
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2115
|
+
async getFormula(options) {
|
|
2116
|
+
const {
|
|
2117
|
+
filters = this.props.filters,
|
|
2118
|
+
filterOwner,
|
|
2119
|
+
spatialFilter,
|
|
2120
|
+
spatialFiltersMode,
|
|
2121
|
+
spatialIndexReferenceViewState,
|
|
2122
|
+
abortController,
|
|
2123
|
+
operationExp
|
|
2124
|
+
} = options,
|
|
2125
|
+
params = _objectWithoutPropertiesLoose(options, _excluded3);
|
|
2126
|
+
const {
|
|
2127
|
+
column,
|
|
2128
|
+
operation
|
|
2129
|
+
} = params;
|
|
2130
|
+
const source = this.getModelSource(filters, filterOwner);
|
|
2131
|
+
const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
2132
|
+
return executeModel({
|
|
2133
|
+
model: 'formula',
|
|
2134
|
+
source: _extends({}, source, {
|
|
2135
|
+
spatialFiltersResolution,
|
|
2136
|
+
spatialFiltersMode,
|
|
2137
|
+
spatialFilter
|
|
2138
|
+
}),
|
|
2139
|
+
params: {
|
|
2140
|
+
column: column != null ? column : '*',
|
|
2141
|
+
operation: operation != null ? operation : 'count',
|
|
2142
|
+
operationExp
|
|
2143
|
+
},
|
|
2144
|
+
opts: {
|
|
2145
|
+
abortController,
|
|
2146
|
+
headers: this._headers
|
|
2147
|
+
}
|
|
2148
|
+
}).then(res => normalizeObjectKeys(res.rows[0]));
|
|
2138
2149
|
}
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2150
|
+
async getHistogram(options) {
|
|
2151
|
+
const {
|
|
2152
|
+
filters = this.props.filters,
|
|
2153
|
+
filterOwner,
|
|
2154
|
+
spatialFilter,
|
|
2155
|
+
spatialFiltersMode,
|
|
2156
|
+
spatialIndexReferenceViewState,
|
|
2157
|
+
abortController
|
|
2158
|
+
} = options,
|
|
2159
|
+
params = _objectWithoutPropertiesLoose(options, _excluded4);
|
|
2160
|
+
const {
|
|
2161
|
+
column,
|
|
2162
|
+
operation,
|
|
2163
|
+
ticks
|
|
2164
|
+
} = params;
|
|
2165
|
+
const source = this.getModelSource(filters, filterOwner);
|
|
2166
|
+
const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
2167
|
+
const data = await executeModel({
|
|
2168
|
+
model: 'histogram',
|
|
2169
|
+
source: _extends({}, source, {
|
|
2170
|
+
spatialFiltersResolution,
|
|
2171
|
+
spatialFiltersMode,
|
|
2172
|
+
spatialFilter
|
|
2173
|
+
}),
|
|
2174
|
+
params: {
|
|
2175
|
+
column,
|
|
2176
|
+
operation,
|
|
2177
|
+
ticks
|
|
2178
|
+
},
|
|
2179
|
+
opts: {
|
|
2180
|
+
abortController,
|
|
2181
|
+
headers: this._headers
|
|
2182
|
+
}
|
|
2183
|
+
}).then(res => normalizeObjectKeys(res.rows));
|
|
2184
|
+
if (data.length) {
|
|
2185
|
+
// Given N ticks the API returns up to N+1 bins, omitting any empty bins. Bins
|
|
2186
|
+
// include 1 bin below the lowest tick, N-1 between ticks, and 1 bin above the highest tick.
|
|
2187
|
+
const result = Array(ticks.length + 1).fill(0);
|
|
2188
|
+
data.forEach(({
|
|
2189
|
+
tick,
|
|
2190
|
+
value
|
|
2191
|
+
}) => result[tick] = value);
|
|
2192
|
+
return result;
|
|
2193
|
+
}
|
|
2194
|
+
return [];
|
|
2144
2195
|
}
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2196
|
+
async getRange(options) {
|
|
2197
|
+
const {
|
|
2198
|
+
filters = this.props.filters,
|
|
2199
|
+
filterOwner,
|
|
2200
|
+
spatialFilter,
|
|
2201
|
+
spatialFiltersMode,
|
|
2202
|
+
spatialIndexReferenceViewState,
|
|
2203
|
+
abortController
|
|
2204
|
+
} = options,
|
|
2205
|
+
params = _objectWithoutPropertiesLoose(options, _excluded5);
|
|
2206
|
+
const {
|
|
2207
|
+
column
|
|
2208
|
+
} = params;
|
|
2209
|
+
const source = this.getModelSource(filters, filterOwner);
|
|
2210
|
+
const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
2211
|
+
return executeModel({
|
|
2212
|
+
model: 'range',
|
|
2213
|
+
source: _extends({}, source, {
|
|
2214
|
+
spatialFiltersResolution,
|
|
2215
|
+
spatialFiltersMode,
|
|
2216
|
+
spatialFilter
|
|
2217
|
+
}),
|
|
2218
|
+
params: {
|
|
2219
|
+
column
|
|
2220
|
+
},
|
|
2221
|
+
opts: {
|
|
2222
|
+
abortController,
|
|
2223
|
+
headers: this._headers
|
|
2224
|
+
}
|
|
2225
|
+
}).then(res => normalizeObjectKeys(res.rows[0]));
|
|
2154
2226
|
}
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2227
|
+
async getScatter(options) {
|
|
2228
|
+
const {
|
|
2229
|
+
filters = this.props.filters,
|
|
2230
|
+
filterOwner,
|
|
2231
|
+
spatialFilter,
|
|
2232
|
+
spatialFiltersMode,
|
|
2233
|
+
spatialIndexReferenceViewState,
|
|
2234
|
+
abortController
|
|
2235
|
+
} = options,
|
|
2236
|
+
params = _objectWithoutPropertiesLoose(options, _excluded6);
|
|
2237
|
+
const {
|
|
2238
|
+
xAxisColumn,
|
|
2239
|
+
xAxisJoinOperation,
|
|
2240
|
+
yAxisColumn,
|
|
2241
|
+
yAxisJoinOperation
|
|
2242
|
+
} = params;
|
|
2243
|
+
const source = this.getModelSource(filters, filterOwner);
|
|
2244
|
+
const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
2245
|
+
// Make sure this is sync with the same constant in cloud-native/maps-api
|
|
2246
|
+
const HARD_LIMIT = 500;
|
|
2247
|
+
return executeModel({
|
|
2248
|
+
model: 'scatterplot',
|
|
2249
|
+
source: _extends({}, source, {
|
|
2250
|
+
spatialFiltersResolution,
|
|
2251
|
+
spatialFiltersMode,
|
|
2252
|
+
spatialFilter
|
|
2253
|
+
}),
|
|
2254
|
+
params: {
|
|
2255
|
+
xAxisColumn,
|
|
2256
|
+
xAxisJoinOperation,
|
|
2257
|
+
yAxisColumn,
|
|
2258
|
+
yAxisJoinOperation,
|
|
2259
|
+
limit: HARD_LIMIT
|
|
2260
|
+
},
|
|
2261
|
+
opts: {
|
|
2262
|
+
abortController,
|
|
2263
|
+
headers: this._headers
|
|
2264
|
+
}
|
|
2265
|
+
}).then(res => normalizeObjectKeys(res.rows)).then(res => res.map(({
|
|
2266
|
+
x,
|
|
2267
|
+
y
|
|
2268
|
+
}) => [x, y]));
|
|
2167
2269
|
}
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2270
|
+
async getTable(options) {
|
|
2271
|
+
const {
|
|
2272
|
+
filters = this.props.filters,
|
|
2273
|
+
filterOwner,
|
|
2274
|
+
spatialFilter,
|
|
2275
|
+
spatialFiltersMode,
|
|
2276
|
+
spatialIndexReferenceViewState,
|
|
2277
|
+
abortController
|
|
2278
|
+
} = options,
|
|
2279
|
+
params = _objectWithoutPropertiesLoose(options, _excluded7);
|
|
2280
|
+
const {
|
|
2281
|
+
columns,
|
|
2282
|
+
sortBy,
|
|
2283
|
+
sortDirection,
|
|
2284
|
+
offset = 0,
|
|
2285
|
+
limit = 10
|
|
2286
|
+
} = params;
|
|
2287
|
+
const source = this.getModelSource(filters, filterOwner);
|
|
2288
|
+
const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
2289
|
+
return executeModel({
|
|
2290
|
+
model: 'table',
|
|
2291
|
+
source: _extends({}, source, {
|
|
2292
|
+
spatialFiltersResolution,
|
|
2293
|
+
spatialFiltersMode,
|
|
2294
|
+
spatialFilter
|
|
2295
|
+
}),
|
|
2296
|
+
params: {
|
|
2297
|
+
column: columns,
|
|
2298
|
+
sortBy,
|
|
2299
|
+
sortDirection,
|
|
2300
|
+
limit,
|
|
2301
|
+
offset
|
|
2302
|
+
},
|
|
2303
|
+
opts: {
|
|
2304
|
+
abortController,
|
|
2305
|
+
headers: this._headers
|
|
2197
2306
|
}
|
|
2198
|
-
|
|
2199
|
-
|
|
2307
|
+
}).then(res => {
|
|
2308
|
+
var _res$rows, _res$metadata$total, _res$metadata, _res$METADATA;
|
|
2309
|
+
return {
|
|
2310
|
+
// Avoid `normalizeObjectKeys()`, which changes column names.
|
|
2311
|
+
rows: (_res$rows = res.rows) != null ? _res$rows : res.ROWS,
|
|
2312
|
+
totalCount: (_res$metadata$total = (_res$metadata = res.metadata) == null ? void 0 : _res$metadata.total) != null ? _res$metadata$total : (_res$METADATA = res.METADATA) == null ? void 0 : _res$METADATA.TOTAL
|
|
2313
|
+
};
|
|
2314
|
+
});
|
|
2315
|
+
}
|
|
2316
|
+
async getTimeSeries(options) {
|
|
2317
|
+
const {
|
|
2318
|
+
filters = this.props.filters,
|
|
2319
|
+
filterOwner,
|
|
2320
|
+
abortController,
|
|
2321
|
+
spatialFilter,
|
|
2322
|
+
spatialFiltersMode,
|
|
2323
|
+
spatialIndexReferenceViewState
|
|
2324
|
+
} = options,
|
|
2325
|
+
params = _objectWithoutPropertiesLoose(options, _excluded8);
|
|
2326
|
+
const {
|
|
2327
|
+
column,
|
|
2328
|
+
operationColumn,
|
|
2329
|
+
joinOperation,
|
|
2330
|
+
operation,
|
|
2331
|
+
stepSize,
|
|
2332
|
+
stepMultiplier,
|
|
2333
|
+
splitByCategory,
|
|
2334
|
+
splitByCategoryLimit,
|
|
2335
|
+
splitByCategoryValues
|
|
2336
|
+
} = params;
|
|
2337
|
+
const source = this.getModelSource(filters, filterOwner);
|
|
2338
|
+
const spatialFiltersResolution = this._getSpatialFiltersResolution(source, spatialFilter, spatialIndexReferenceViewState);
|
|
2339
|
+
return executeModel({
|
|
2340
|
+
model: 'timeseries',
|
|
2341
|
+
source: _extends({}, source, {
|
|
2342
|
+
spatialFiltersResolution,
|
|
2343
|
+
spatialFiltersMode,
|
|
2344
|
+
spatialFilter
|
|
2345
|
+
}),
|
|
2346
|
+
params: {
|
|
2347
|
+
column,
|
|
2348
|
+
stepSize,
|
|
2349
|
+
stepMultiplier,
|
|
2350
|
+
operationColumn: operationColumn || column,
|
|
2351
|
+
joinOperation,
|
|
2352
|
+
operation,
|
|
2353
|
+
splitByCategory,
|
|
2354
|
+
splitByCategoryLimit,
|
|
2355
|
+
splitByCategoryValues
|
|
2356
|
+
},
|
|
2357
|
+
opts: {
|
|
2358
|
+
abortController,
|
|
2359
|
+
headers: this._headers
|
|
2200
2360
|
}
|
|
2201
|
-
}
|
|
2361
|
+
}).then(res => {
|
|
2362
|
+
var _res$metadata2;
|
|
2363
|
+
return {
|
|
2364
|
+
rows: normalizeObjectKeys(res.rows),
|
|
2365
|
+
categories: (_res$metadata2 = res.metadata) == null ? void 0 : _res$metadata2.categories
|
|
2366
|
+
};
|
|
2367
|
+
});
|
|
2202
2368
|
}
|
|
2203
|
-
return Array.from(data.values());
|
|
2204
|
-
}
|
|
2205
|
-
/**
|
|
2206
|
-
* Detects whether a given {@link Tile} is a {@link RasterTile}.
|
|
2207
|
-
* @privateRemarks Method of detection is arbitrary, and may be changed.
|
|
2208
|
-
*/
|
|
2209
|
-
function isRasterTile(tile) {
|
|
2210
|
-
return tile.data ? tile.data.hasOwnProperty('cells') : false;
|
|
2211
|
-
}
|
|
2212
|
-
function isRasterTileVisible(tile) {
|
|
2213
|
-
var _tile$data;
|
|
2214
|
-
return !!(tile.isVisible && (_tile$data = tile.data) != null && (_tile$data = _tile$data.cells) != null && _tile$data.numericProps);
|
|
2215
2369
|
}
|
|
2370
|
+
|
|
2216
2371
|
/**
|
|
2217
|
-
*
|
|
2218
|
-
*
|
|
2219
|
-
*
|
|
2372
|
+
* Source for Widget API requests on a data source defined by a SQL query.
|
|
2373
|
+
*
|
|
2374
|
+
* Generally not intended to be constructed directly. Instead, call
|
|
2375
|
+
* {@link vectorQuerySource}, {@link h3QuerySource}, or {@link quadbinQuerySource},
|
|
2376
|
+
* which can be shared with map layers. Sources contain a `widgetSource` property,
|
|
2377
|
+
* for use by widget implementations.
|
|
2378
|
+
*
|
|
2379
|
+
* Example:
|
|
2380
|
+
*
|
|
2381
|
+
* ```javascript
|
|
2382
|
+
* import { vectorQuerySource } from '@carto/api-client';
|
|
2383
|
+
*
|
|
2384
|
+
* const data = vectorQuerySource({
|
|
2385
|
+
* accessToken: '••••',
|
|
2386
|
+
* connectionName: 'carto_dw',
|
|
2387
|
+
* sqlQuery: 'SELECT * FROM carto-demo-data.demo_tables.retail_stores'
|
|
2388
|
+
* });
|
|
2389
|
+
*
|
|
2390
|
+
* const { widgetSource } = await data;
|
|
2391
|
+
* ```
|
|
2220
2392
|
*/
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
}
|
|
2228
|
-
return tileA.x > tileB.x ? 1 : -1;
|
|
2229
|
-
});
|
|
2230
|
-
}
|
|
2231
|
-
|
|
2232
|
-
/** @internalRemarks Source: @carto/react-core */
|
|
2233
|
-
function tileFeatures({
|
|
2234
|
-
tiles,
|
|
2235
|
-
spatialFilter,
|
|
2236
|
-
uniqueIdProperty,
|
|
2237
|
-
tileFormat,
|
|
2238
|
-
spatialDataColumn = DEFAULT_GEO_COLUMN,
|
|
2239
|
-
spatialDataType,
|
|
2240
|
-
rasterMetadata,
|
|
2241
|
-
options = {}
|
|
2242
|
-
}) {
|
|
2243
|
-
// TODO(cleanup): Is an empty response the expected result when spatialFilter
|
|
2244
|
-
// is omitted? Why not make the parameter required, or return the full input?
|
|
2245
|
-
if (!spatialFilter) {
|
|
2246
|
-
return [];
|
|
2247
|
-
}
|
|
2248
|
-
if (spatialDataType === 'geo') {
|
|
2249
|
-
return tileFeaturesGeometries({
|
|
2250
|
-
tiles,
|
|
2251
|
-
tileFormat,
|
|
2252
|
-
spatialFilter,
|
|
2253
|
-
uniqueIdProperty,
|
|
2254
|
-
options
|
|
2255
|
-
});
|
|
2256
|
-
}
|
|
2257
|
-
if (tiles.some(isRasterTile)) {
|
|
2258
|
-
assert$1(rasterMetadata, 'Missing raster metadata');
|
|
2259
|
-
return tileFeaturesRaster({
|
|
2260
|
-
tiles: tiles,
|
|
2261
|
-
spatialFilter,
|
|
2262
|
-
spatialDataColumn,
|
|
2263
|
-
spatialDataType,
|
|
2264
|
-
rasterMetadata
|
|
2393
|
+
class WidgetQuerySource extends WidgetRemoteSource {
|
|
2394
|
+
getModelSource(filters, filterOwner) {
|
|
2395
|
+
return _extends({}, super._getModelSource(filters, filterOwner), {
|
|
2396
|
+
type: 'query',
|
|
2397
|
+
data: this.props.sqlQuery,
|
|
2398
|
+
queryParameters: this.props.queryParameters
|
|
2265
2399
|
});
|
|
2266
2400
|
}
|
|
2267
|
-
return tileFeaturesSpatialIndex({
|
|
2268
|
-
tiles: tiles,
|
|
2269
|
-
spatialFilter,
|
|
2270
|
-
spatialDataColumn,
|
|
2271
|
-
spatialDataType
|
|
2272
|
-
});
|
|
2273
2401
|
}
|
|
2274
2402
|
|
|
2275
|
-
/** @
|
|
2403
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
2276
2404
|
const aggregationFunctions = {
|
|
2277
2405
|
count: values => values.length,
|
|
2278
2406
|
min: (...args) => applyAggregationFunction(min, ...args),
|
|
@@ -2280,7 +2408,7 @@ const aggregationFunctions = {
|
|
|
2280
2408
|
sum: (...args) => applyAggregationFunction(sum, ...args),
|
|
2281
2409
|
avg: (...args) => applyAggregationFunction(avg, ...args)
|
|
2282
2410
|
};
|
|
2283
|
-
/** @
|
|
2411
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
2284
2412
|
function aggregate(feature, keys, operation) {
|
|
2285
2413
|
if (!(keys != null && keys.length)) {
|
|
2286
2414
|
throw new Error('Cannot aggregate a feature without having keys');
|
|
@@ -2429,7 +2557,7 @@ var thenBy_module = function () {
|
|
|
2429
2557
|
* @param [sortOptions.sortByDirection] - Direction by the columns will be sorted
|
|
2430
2558
|
* @param [sortOptions.sortByColumnType] - Column type
|
|
2431
2559
|
* @internal
|
|
2432
|
-
* @
|
|
2560
|
+
* @privateRemarks Source: @carto/react-core
|
|
2433
2561
|
*/
|
|
2434
2562
|
function applySorting(features, {
|
|
2435
2563
|
sortBy,
|
|
@@ -2466,7 +2594,7 @@ function createSortFn({
|
|
|
2466
2594
|
sortByColumnType
|
|
2467
2595
|
});
|
|
2468
2596
|
let sortFn = thenBy_module.firstBy(...firstSortOption);
|
|
2469
|
-
for (
|
|
2597
|
+
for (const sortOptions of othersSortOptions) {
|
|
2470
2598
|
sortFn = sortFn.thenBy(...sortOptions);
|
|
2471
2599
|
}
|
|
2472
2600
|
return sortFn;
|
|
@@ -2508,7 +2636,7 @@ function normalizeSortByOptions({
|
|
|
2508
2636
|
});
|
|
2509
2637
|
}
|
|
2510
2638
|
|
|
2511
|
-
/** @
|
|
2639
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
2512
2640
|
function groupValuesByColumn({
|
|
2513
2641
|
data,
|
|
2514
2642
|
valuesColumns,
|
|
@@ -2566,7 +2694,7 @@ const GROUP_KEY_FN_MAPPING = {
|
|
|
2566
2694
|
minute: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes()),
|
|
2567
2695
|
second: date => Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds())
|
|
2568
2696
|
};
|
|
2569
|
-
/** @
|
|
2697
|
+
/** @privateRemarks Source: @carto/react-core */
|
|
2570
2698
|
function groupValuesByDateColumn({
|
|
2571
2699
|
data,
|
|
2572
2700
|
valuesColumns,
|
|
@@ -2610,7 +2738,7 @@ function groupValuesByDateColumn({
|
|
|
2610
2738
|
|
|
2611
2739
|
/**
|
|
2612
2740
|
* Histogram computation.
|
|
2613
|
-
* @
|
|
2741
|
+
* @privateRemarks Source: @carto/react-core
|
|
2614
2742
|
*/
|
|
2615
2743
|
function histogram({
|
|
2616
2744
|
data,
|
|
@@ -2647,7 +2775,7 @@ function histogram({
|
|
|
2647
2775
|
|
|
2648
2776
|
/**
|
|
2649
2777
|
* Filters invalid features and formats data.
|
|
2650
|
-
* @
|
|
2778
|
+
* @privateRemarks Source: @carto/react-core
|
|
2651
2779
|
*/
|
|
2652
2780
|
function scatterPlot({
|
|
2653
2781
|
data,
|
|
@@ -2668,7 +2796,6 @@ function scatterPlot({
|
|
|
2668
2796
|
}, []);
|
|
2669
2797
|
}
|
|
2670
2798
|
|
|
2671
|
-
const _excluded = ["filterOwner", "spatialFilter", "abortController"];
|
|
2672
2799
|
/**
|
|
2673
2800
|
* Source for Widget API requests on a data source defined by a tileset.
|
|
2674
2801
|
*
|
|
@@ -2696,9 +2823,11 @@ class WidgetTilesetSource extends WidgetSource {
|
|
|
2696
2823
|
super(...args);
|
|
2697
2824
|
this._tiles = [];
|
|
2698
2825
|
this._features = [];
|
|
2826
|
+
this._tileFeatureExtractOptions = {};
|
|
2827
|
+
this._tileFeatureExtractPreviousInputs = {};
|
|
2699
2828
|
}
|
|
2700
|
-
getModelSource(
|
|
2701
|
-
return _extends({}, super._getModelSource(
|
|
2829
|
+
getModelSource(filters, filterOwner) {
|
|
2830
|
+
return _extends({}, super._getModelSource(filters, filterOwner), {
|
|
2702
2831
|
type: 'tileset',
|
|
2703
2832
|
data: this.props.tableName
|
|
2704
2833
|
});
|
|
@@ -2710,57 +2839,60 @@ class WidgetTilesetSource extends WidgetSource {
|
|
|
2710
2839
|
*/
|
|
2711
2840
|
loadTiles(tiles) {
|
|
2712
2841
|
this._tiles = tiles;
|
|
2842
|
+
this._features.length = 0;
|
|
2843
|
+
}
|
|
2844
|
+
/** Configures options used to extract features from tiles. */
|
|
2845
|
+
setTileFeatureExtractOptions(options) {
|
|
2846
|
+
this._tileFeatureExtractOptions = options;
|
|
2847
|
+
this._features.length = 0;
|
|
2848
|
+
}
|
|
2849
|
+
_extractTileFeatures(spatialFilter) {
|
|
2850
|
+
// When spatial filter has not changed, don't redo extraction. If tiles or
|
|
2851
|
+
// tile extract options change, features will have been cleared already.
|
|
2852
|
+
const prevInputs = this._tileFeatureExtractPreviousInputs;
|
|
2853
|
+
if (this._features.length && prevInputs.spatialFilter && booleanEqual(prevInputs.spatialFilter, spatialFilter)) {
|
|
2854
|
+
return;
|
|
2855
|
+
}
|
|
2856
|
+
this._features = tileFeatures(_extends({}, this.props, this._tileFeatureExtractOptions, {
|
|
2857
|
+
tiles: this._tiles,
|
|
2858
|
+
spatialFilter
|
|
2859
|
+
}));
|
|
2860
|
+
prevInputs.spatialFilter = spatialFilter;
|
|
2713
2861
|
}
|
|
2714
2862
|
/**
|
|
2715
|
-
*
|
|
2716
|
-
*
|
|
2863
|
+
* Loads features as GeoJSON (used for testing).
|
|
2864
|
+
* @experimental
|
|
2865
|
+
* @internal Not for public use. Spatial filters in other method calls will be ignored.
|
|
2717
2866
|
*/
|
|
2718
|
-
extractTileFeatures({
|
|
2719
|
-
spatialFilter,
|
|
2720
|
-
uniqueIdProperty,
|
|
2721
|
-
options
|
|
2722
|
-
}) {
|
|
2723
|
-
this._features = tileFeatures(_extends({
|
|
2724
|
-
tiles: this._tiles,
|
|
2725
|
-
options,
|
|
2726
|
-
spatialFilter,
|
|
2727
|
-
uniqueIdProperty
|
|
2728
|
-
}, this.props));
|
|
2729
|
-
}
|
|
2730
|
-
/** Loads features as GeoJSON (used for testing). */
|
|
2731
2867
|
loadGeoJSON({
|
|
2732
2868
|
geojson,
|
|
2733
|
-
spatialFilter
|
|
2734
|
-
uniqueIdProperty
|
|
2869
|
+
spatialFilter
|
|
2735
2870
|
}) {
|
|
2736
|
-
this._features = geojsonFeatures({
|
|
2871
|
+
this._features = geojsonFeatures(_extends({
|
|
2737
2872
|
geojson,
|
|
2738
|
-
spatialFilter
|
|
2739
|
-
|
|
2740
|
-
|
|
2873
|
+
spatialFilter
|
|
2874
|
+
}, this._tileFeatureExtractOptions));
|
|
2875
|
+
this._tileFeatureExtractPreviousInputs.spatialFilter = spatialFilter;
|
|
2741
2876
|
}
|
|
2742
|
-
async getFeatures(
|
|
2877
|
+
async getFeatures() {
|
|
2743
2878
|
throw new Error('getFeatures not supported for tilesets');
|
|
2744
2879
|
}
|
|
2745
2880
|
async getFormula({
|
|
2746
2881
|
column = '*',
|
|
2747
2882
|
operation = 'count',
|
|
2748
2883
|
joinOperation,
|
|
2749
|
-
|
|
2884
|
+
filters,
|
|
2885
|
+
filterOwner,
|
|
2886
|
+
spatialFilter
|
|
2750
2887
|
}) {
|
|
2751
2888
|
if (operation === 'custom') {
|
|
2752
2889
|
throw new Error('Custom aggregation not supported for tilesets');
|
|
2753
2890
|
}
|
|
2754
|
-
if (!this._features.length) {
|
|
2755
|
-
return {
|
|
2756
|
-
value: null
|
|
2757
|
-
};
|
|
2758
|
-
}
|
|
2759
2891
|
// Column is required except when operation is 'count'.
|
|
2760
2892
|
if (column && column !== '*' || operation !== 'count') {
|
|
2761
2893
|
assertColumn(this._features, column);
|
|
2762
2894
|
}
|
|
2763
|
-
const filteredFeatures = this._getFilteredFeatures(filterOwner);
|
|
2895
|
+
const filteredFeatures = this._getFilteredFeatures(spatialFilter, filters, filterOwner);
|
|
2764
2896
|
if (filteredFeatures.length === 0 && operation !== 'count') {
|
|
2765
2897
|
return {
|
|
2766
2898
|
value: null
|
|
@@ -2776,13 +2908,15 @@ class WidgetTilesetSource extends WidgetSource {
|
|
|
2776
2908
|
ticks,
|
|
2777
2909
|
column,
|
|
2778
2910
|
joinOperation,
|
|
2779
|
-
|
|
2911
|
+
filters,
|
|
2912
|
+
filterOwner,
|
|
2913
|
+
spatialFilter
|
|
2780
2914
|
}) {
|
|
2915
|
+
const filteredFeatures = this._getFilteredFeatures(spatialFilter, filters, filterOwner);
|
|
2916
|
+
assertColumn(this._features, column);
|
|
2781
2917
|
if (!this._features.length) {
|
|
2782
2918
|
return [];
|
|
2783
2919
|
}
|
|
2784
|
-
const filteredFeatures = this._getFilteredFeatures(filterOwner);
|
|
2785
|
-
assertColumn(this._features, column);
|
|
2786
2920
|
return histogram({
|
|
2787
2921
|
data: filteredFeatures,
|
|
2788
2922
|
valuesColumns: normalizeColumns(column),
|
|
@@ -2796,12 +2930,14 @@ class WidgetTilesetSource extends WidgetSource {
|
|
|
2796
2930
|
operation = 'count',
|
|
2797
2931
|
operationColumn,
|
|
2798
2932
|
joinOperation,
|
|
2799
|
-
|
|
2933
|
+
filters,
|
|
2934
|
+
filterOwner,
|
|
2935
|
+
spatialFilter
|
|
2800
2936
|
}) {
|
|
2801
|
-
|
|
2937
|
+
const filteredFeatures = this._getFilteredFeatures(spatialFilter, filters, filterOwner);
|
|
2938
|
+
if (!filteredFeatures.length) {
|
|
2802
2939
|
return [];
|
|
2803
2940
|
}
|
|
2804
|
-
const filteredFeatures = this._getFilteredFeatures(filterOwner);
|
|
2805
2941
|
assertColumn(this._features, column, operationColumn);
|
|
2806
2942
|
const groups = groupValuesByColumn({
|
|
2807
2943
|
data: filteredFeatures,
|
|
@@ -2817,12 +2953,14 @@ class WidgetTilesetSource extends WidgetSource {
|
|
|
2817
2953
|
yAxisColumn,
|
|
2818
2954
|
xAxisJoinOperation,
|
|
2819
2955
|
yAxisJoinOperation,
|
|
2820
|
-
|
|
2956
|
+
filters,
|
|
2957
|
+
filterOwner,
|
|
2958
|
+
spatialFilter
|
|
2821
2959
|
}) {
|
|
2822
|
-
|
|
2960
|
+
const filteredFeatures = this._getFilteredFeatures(spatialFilter, filters, filterOwner);
|
|
2961
|
+
if (!filteredFeatures.length) {
|
|
2823
2962
|
return [];
|
|
2824
2963
|
}
|
|
2825
|
-
const filteredFeatures = this._getFilteredFeatures(filterOwner);
|
|
2826
2964
|
assertColumn(this._features, xAxisColumn, yAxisColumn);
|
|
2827
2965
|
return scatterPlot({
|
|
2828
2966
|
data: filteredFeatures,
|
|
@@ -2832,31 +2970,28 @@ class WidgetTilesetSource extends WidgetSource {
|
|
|
2832
2970
|
yAxisJoinOperation
|
|
2833
2971
|
});
|
|
2834
2972
|
}
|
|
2835
|
-
async getTable(
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
if (!
|
|
2973
|
+
async getTable({
|
|
2974
|
+
columns,
|
|
2975
|
+
searchFilterColumn,
|
|
2976
|
+
searchFilterText,
|
|
2977
|
+
sortBy,
|
|
2978
|
+
sortDirection,
|
|
2979
|
+
sortByColumnType,
|
|
2980
|
+
offset = 0,
|
|
2981
|
+
limit = 10,
|
|
2982
|
+
filters,
|
|
2983
|
+
filterOwner,
|
|
2984
|
+
spatialFilter
|
|
2985
|
+
}) {
|
|
2986
|
+
// Filter.
|
|
2987
|
+
let filteredFeatures = this._getFilteredFeatures(spatialFilter, filters, filterOwner);
|
|
2988
|
+
if (!filteredFeatures.length) {
|
|
2851
2989
|
return {
|
|
2852
2990
|
rows: [],
|
|
2853
2991
|
totalCount: 0
|
|
2854
2992
|
};
|
|
2855
2993
|
}
|
|
2856
|
-
// Filter.
|
|
2857
|
-
let filteredFeatures = this._getFilteredFeatures(filterOwner);
|
|
2858
2994
|
// Search.
|
|
2859
|
-
// TODO: Could we get the same behavior by applying filters in loadTiles()?
|
|
2860
2995
|
if (searchFilterColumn && searchFilterText) {
|
|
2861
2996
|
filteredFeatures = filteredFeatures.filter(row => row[searchFilterColumn] && String(row[searchFilterColumn]).toLowerCase().includes(String(searchFilterText).toLowerCase()));
|
|
2862
2997
|
}
|
|
@@ -2888,14 +3023,16 @@ class WidgetTilesetSource extends WidgetSource {
|
|
|
2888
3023
|
operation,
|
|
2889
3024
|
operationColumn,
|
|
2890
3025
|
joinOperation,
|
|
2891
|
-
|
|
3026
|
+
filters,
|
|
3027
|
+
filterOwner,
|
|
3028
|
+
spatialFilter
|
|
2892
3029
|
}) {
|
|
2893
|
-
|
|
3030
|
+
const filteredFeatures = this._getFilteredFeatures(spatialFilter, filters, filterOwner);
|
|
3031
|
+
if (!filteredFeatures.length) {
|
|
2894
3032
|
return {
|
|
2895
3033
|
rows: []
|
|
2896
3034
|
};
|
|
2897
3035
|
}
|
|
2898
|
-
const filteredFeatures = this._getFilteredFeatures(filterOwner);
|
|
2899
3036
|
assertColumn(this._features, column, operationColumn);
|
|
2900
3037
|
const rows = groupValuesByDateColumn({
|
|
2901
3038
|
data: filteredFeatures,
|
|
@@ -2911,15 +3048,17 @@ class WidgetTilesetSource extends WidgetSource {
|
|
|
2911
3048
|
}
|
|
2912
3049
|
async getRange({
|
|
2913
3050
|
column,
|
|
2914
|
-
|
|
3051
|
+
filters,
|
|
3052
|
+
filterOwner,
|
|
3053
|
+
spatialFilter
|
|
2915
3054
|
}) {
|
|
3055
|
+
assertColumn(this._features, column);
|
|
3056
|
+
const filteredFeatures = this._getFilteredFeatures(spatialFilter, filters, filterOwner);
|
|
2916
3057
|
if (!this._features.length) {
|
|
2917
3058
|
// TODO: Is this the only nullable response in the Widgets API? If so,
|
|
2918
3059
|
// can we do something more consistent?
|
|
2919
3060
|
return null;
|
|
2920
3061
|
}
|
|
2921
|
-
assertColumn(this._features, column);
|
|
2922
|
-
const filteredFeatures = this._getFilteredFeatures(filterOwner);
|
|
2923
3062
|
return {
|
|
2924
3063
|
min: aggregationFunctions.min(filteredFeatures, column),
|
|
2925
3064
|
max: aggregationFunctions.max(filteredFeatures, column)
|
|
@@ -2928,8 +3067,10 @@ class WidgetTilesetSource extends WidgetSource {
|
|
|
2928
3067
|
/****************************************************************************
|
|
2929
3068
|
* INTERNAL
|
|
2930
3069
|
*/
|
|
2931
|
-
_getFilteredFeatures(filterOwner) {
|
|
2932
|
-
|
|
3070
|
+
_getFilteredFeatures(spatialFilter, filters, filterOwner) {
|
|
3071
|
+
assert(spatialFilter, 'spatialFilter required for tilesets');
|
|
3072
|
+
this._extractTileFeatures(spatialFilter);
|
|
3073
|
+
return applyFilters(this._features, getApplicableFilters(filterOwner, filters || this.props.filters), this.props.filtersLogicalOperator || 'and');
|
|
2933
3074
|
}
|
|
2934
3075
|
}
|
|
2935
3076
|
function assertColumn(features, ...columnArgs) {
|
|
@@ -2971,8 +3112,8 @@ class WidgetRasterSource extends WidgetTilesetSource {}
|
|
|
2971
3112
|
* ```
|
|
2972
3113
|
*/
|
|
2973
3114
|
class WidgetTableSource extends WidgetRemoteSource {
|
|
2974
|
-
getModelSource(
|
|
2975
|
-
return _extends({}, super._getModelSource(
|
|
3115
|
+
getModelSource(filters, filterOwner) {
|
|
3116
|
+
return _extends({}, super._getModelSource(filters, filterOwner), {
|
|
2976
3117
|
type: 'table',
|
|
2977
3118
|
data: this.props.tableName
|
|
2978
3119
|
});
|
|
@@ -3300,5 +3441,5 @@ const query = async function query(options) {
|
|
|
3300
3441
|
});
|
|
3301
3442
|
};
|
|
3302
3443
|
|
|
3303
|
-
export { ApiVersion, CartoAPIError, DEFAULT_API_BASE_URL, FEATURE_GEOM_PROPERTY, FilterType, Provider, SOURCE_DEFAULTS, SpatialIndex, TileFormat, WidgetQuerySource, WidgetRasterSource, WidgetRemoteSource, WidgetSource, WidgetTableSource, WidgetTilesetSource, _getHexagonResolution, addFilter, aggregate, aggregationFunctions, applyFilters, applySorting, boundaryQuerySource, boundaryTableSource, buildBinaryFeatureFilter,
|
|
3444
|
+
export { ApiVersion, CartoAPIError, DEFAULT_API_BASE_URL, FEATURE_GEOM_PROPERTY, FilterType, Provider, SOURCE_DEFAULTS, SpatialIndex, TileFormat, WidgetQuerySource, WidgetRasterSource, WidgetRemoteSource, WidgetSource, WidgetTableSource, WidgetTilesetSource, _buildFeatureFilter, _getHexagonResolution, addFilter, aggregate, aggregationFunctions, applyFilters, applySorting, boundaryQuerySource, boundaryTableSource, buildBinaryFeatureFilter, buildPublicMapUrl, buildStatsUrl, clearFilters, createPolygonSpatialFilter, createViewportSpatialFilter, filterFunctions, geojsonFeatures, getClient, getDataFilterExtensionProps, getFilter, groupValuesByColumn, groupValuesByDateColumn, h3QuerySource, h3TableSource, h3TilesetSource, hasFilter, histogram, makeIntervalComplete, quadbinQuerySource, quadbinTableSource, quadbinTilesetSource, query, rasterSource, removeFilter, requestWithParameters, scatterPlot, setClient, tileFeatures, tileFeaturesGeometries, tileFeaturesSpatialIndex, transformToTileCoords, vectorQuerySource, vectorTableSource, vectorTilesetSource };
|
|
3304
3445
|
//# sourceMappingURL=api-client.modern.js.map
|