@carto/api-client 0.4.6-0 → 0.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/build/api-client.cjs +208 -2167
- package/build/api-client.cjs.map +1 -1
- package/build/api-client.modern.js +208 -2040
- package/build/api-client.modern.js.map +1 -1
- package/build/constants.d.ts +0 -22
- package/build/index.d.ts +1 -4
- package/build/models/index.d.ts +1 -1
- package/build/sources/h3-tileset-source.d.ts +1 -2
- package/build/sources/index.d.ts +1 -1
- package/build/sources/quadbin-tileset-source.d.ts +1 -2
- package/build/sources/vector-tileset-source.d.ts +1 -2
- package/build/spatial-index.d.ts +7 -1
- package/build/types-internal.d.ts +0 -4
- package/build/types.d.ts +1 -61
- package/build/widget-sources/index.d.ts +1 -3
- package/build/widget-sources/types.d.ts +22 -31
- package/build/widget-sources/{widget-source.d.ts → widget-base-source.d.ts} +38 -13
- package/build/widget-sources/widget-query-source.d.ts +2 -2
- package/build/widget-sources/widget-table-source.d.ts +2 -2
- package/package.json +11 -14
- package/src/constants.ts +0 -25
- package/src/index.ts +1 -5
- package/src/models/index.ts +1 -1
- package/src/sources/h3-tileset-source.ts +6 -18
- package/src/sources/index.ts +1 -1
- package/src/sources/quadbin-tileset-source.ts +6 -18
- package/src/sources/raster-source.ts +0 -1
- package/src/sources/vector-query-source.ts +2 -5
- package/src/sources/vector-table-source.ts +2 -5
- package/src/sources/vector-tileset-source.ts +6 -19
- package/src/spatial-index.ts +8 -5
- package/src/types-internal.ts +0 -6
- package/src/types.ts +2 -60
- package/src/widget-sources/index.ts +1 -3
- package/src/widget-sources/types.ts +22 -32
- package/src/widget-sources/{widget-remote-source.ts → widget-base-source.ts} +147 -12
- package/src/widget-sources/widget-query-source.ts +3 -6
- package/src/widget-sources/widget-table-source.ts +3 -6
- package/build/filters/Filter.d.ts +0 -13
- package/build/filters/FilterTypes.d.ts +0 -3
- package/build/filters/geosjonFeatures.d.ts +0 -8
- package/build/filters/index.d.ts +0 -6
- package/build/filters/tileFeatures.d.ts +0 -20
- package/build/filters/tileFeaturesGeometries.d.ts +0 -13
- package/build/filters/tileFeaturesSpatialIndex.d.ts +0 -10
- package/build/operations/aggregation.d.ts +0 -8
- package/build/operations/applySorting.d.ts +0 -20
- package/build/operations/groupBy.d.ts +0 -15
- package/build/operations/groupByDate.d.ts +0 -11
- package/build/operations/histogram.d.ts +0 -13
- package/build/operations/index.d.ts +0 -6
- package/build/operations/scatterPlot.d.ts +0 -14
- package/build/utils/dateUtils.d.ts +0 -10
- package/build/utils/getTileFormat.d.ts +0 -3
- package/build/utils/makeIntervalComplete.d.ts +0 -2
- package/build/utils/transformTileCoordsToWGS84.d.ts +0 -8
- package/build/utils/transformToTileCoords.d.ts +0 -9
- package/build/widget-sources/widget-remote-source.d.ts +0 -18
- package/build/widget-sources/widget-tileset-source.d.ts +0 -76
- package/src/filters/Filter.ts +0 -169
- package/src/filters/FilterTypes.ts +0 -109
- package/src/filters/geosjonFeatures.ts +0 -32
- package/src/filters/index.ts +0 -6
- package/src/filters/tileFeatures.ts +0 -56
- package/src/filters/tileFeaturesGeometries.ts +0 -444
- package/src/filters/tileFeaturesSpatialIndex.ts +0 -119
- package/src/operations/aggregation.ts +0 -154
- package/src/operations/applySorting.ts +0 -109
- package/src/operations/groupBy.ts +0 -59
- package/src/operations/groupByDate.ts +0 -98
- package/src/operations/histogram.ts +0 -66
- package/src/operations/index.ts +0 -6
- package/src/operations/scatterPlot.ts +0 -50
- package/src/utils/dateUtils.ts +0 -28
- package/src/utils/getTileFormat.ts +0 -9
- package/src/utils/makeIntervalComplete.ts +0 -17
- package/src/utils/transformTileCoordsToWGS84.ts +0 -77
- package/src/utils/transformToTileCoords.ts +0 -85
- package/src/widget-sources/widget-source.ts +0 -160
- package/src/widget-sources/widget-tileset-source.ts +0 -407
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import {lngLatToWorld} from '@math.gl/web-mercator';
|
|
2
|
-
import {BBox, GeoJsonGeometryTypes, Geometry, Position} from 'geojson';
|
|
3
|
-
|
|
4
|
-
type TransformFn = (coordinates: any[], bbox: Position[]) => any[];
|
|
5
|
-
|
|
6
|
-
const TRANSFORM_FN: Record<
|
|
7
|
-
Exclude<GeoJsonGeometryTypes, 'GeometryCollection'>,
|
|
8
|
-
TransformFn
|
|
9
|
-
> = {
|
|
10
|
-
Point: transformPoint,
|
|
11
|
-
MultiPoint: transformMultiPoint,
|
|
12
|
-
LineString: transformLineString,
|
|
13
|
-
MultiLineString: transformMultiLineString,
|
|
14
|
-
Polygon: transformPolygon,
|
|
15
|
-
MultiPolygon: transformMultiPolygon,
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Transform WGS84 coordinates to tile coords.
|
|
20
|
-
* 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)
|
|
21
|
-
*
|
|
22
|
-
* @param geometry - any valid geojson geometry
|
|
23
|
-
* @param bbox - geojson bbox
|
|
24
|
-
*/
|
|
25
|
-
export function transformToTileCoords<T extends Geometry>(
|
|
26
|
-
geometry: T,
|
|
27
|
-
bbox: BBox
|
|
28
|
-
): T {
|
|
29
|
-
const [west, south, east, north] = bbox;
|
|
30
|
-
const nw = projectFlat([west, north]);
|
|
31
|
-
const se = projectFlat([east, south]);
|
|
32
|
-
const projectedBbox = [nw, se];
|
|
33
|
-
|
|
34
|
-
if (geometry.type === 'GeometryCollection') {
|
|
35
|
-
throw new Error('Unsupported geometry type GeometryCollection');
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const transformFn = TRANSFORM_FN[geometry.type];
|
|
39
|
-
const coordinates = transformFn(geometry.coordinates, projectedBbox);
|
|
40
|
-
return {...geometry, coordinates};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function transformPoint([pointX, pointY]: Position, [nw, se]: Position[]) {
|
|
44
|
-
const x = inverseLerp(nw[0], se[0], pointX);
|
|
45
|
-
const y = inverseLerp(nw[1], se[1], pointY);
|
|
46
|
-
|
|
47
|
-
return [x, y];
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function getPoints(geometry: Position[], bbox: Position[]) {
|
|
51
|
-
return geometry.map((g) => transformPoint(projectFlat(g), bbox));
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function transformMultiPoint(multiPoint: Position[], bbox: Position[]) {
|
|
55
|
-
return getPoints(multiPoint, bbox);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function transformLineString(line: Position[], bbox: Position[]) {
|
|
59
|
-
return getPoints(line, bbox);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function transformMultiLineString(
|
|
63
|
-
multiLineString: Position[][],
|
|
64
|
-
bbox: Position[]
|
|
65
|
-
) {
|
|
66
|
-
return multiLineString.map((lineString) =>
|
|
67
|
-
transformLineString(lineString, bbox)
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function transformPolygon(polygon: Position[][], bbox: Position[]) {
|
|
72
|
-
return polygon.map((polygonRing) => getPoints(polygonRing, bbox));
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function transformMultiPolygon(multiPolygon: Position[][][], bbox: Position[]) {
|
|
76
|
-
return multiPolygon.map((polygon) => transformPolygon(polygon, bbox));
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function projectFlat(xyz: Position): Position {
|
|
80
|
-
return lngLatToWorld(xyz);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function inverseLerp(a: number, b: number, x: number): number {
|
|
84
|
-
return (x - a) / (b - a);
|
|
85
|
-
}
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
CategoryRequestOptions,
|
|
3
|
-
CategoryResponse,
|
|
4
|
-
FeaturesRequestOptions,
|
|
5
|
-
FeaturesResponse,
|
|
6
|
-
FormulaRequestOptions,
|
|
7
|
-
FormulaResponse,
|
|
8
|
-
HistogramRequestOptions,
|
|
9
|
-
HistogramResponse,
|
|
10
|
-
RangeRequestOptions,
|
|
11
|
-
RangeResponse,
|
|
12
|
-
ScatterRequestOptions,
|
|
13
|
-
ScatterResponse,
|
|
14
|
-
TableRequestOptions,
|
|
15
|
-
TableResponse,
|
|
16
|
-
TimeSeriesRequestOptions,
|
|
17
|
-
TimeSeriesResponse,
|
|
18
|
-
ViewState,
|
|
19
|
-
} from './types.js';
|
|
20
|
-
import {FilterLogicalOperator, Filter, SpatialFilter} from '../types.js';
|
|
21
|
-
import {getApplicableFilters} from '../utils.js';
|
|
22
|
-
import {getClient} from '../client.js';
|
|
23
|
-
import {ModelSource} from '../models/model.js';
|
|
24
|
-
import {SourceOptions} from '../sources/index.js';
|
|
25
|
-
import {ApiVersion, DEFAULT_API_BASE_URL} from '../constants.js';
|
|
26
|
-
import {getSpatialFiltersResolution} from '../spatial-index.js';
|
|
27
|
-
import {AggregationOptions} from '../sources/types.js';
|
|
28
|
-
|
|
29
|
-
export interface WidgetSourceProps extends Omit<SourceOptions, 'filters'> {
|
|
30
|
-
apiVersion?: ApiVersion;
|
|
31
|
-
filters?: Record<string, Filter>;
|
|
32
|
-
filtersLogicalOperator?: FilterLogicalOperator;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Source for Widget API requests on a data source defined by a SQL query.
|
|
37
|
-
*
|
|
38
|
-
* Abstract class. Use {@link WidgetQuerySource} or {@link WidgetTableSource}.
|
|
39
|
-
*/
|
|
40
|
-
export abstract class WidgetSource<Props extends WidgetSourceProps> {
|
|
41
|
-
readonly props: Props;
|
|
42
|
-
|
|
43
|
-
static defaultProps: Partial<WidgetSourceProps> = {
|
|
44
|
-
apiVersion: ApiVersion.V3,
|
|
45
|
-
apiBaseUrl: DEFAULT_API_BASE_URL,
|
|
46
|
-
clientId: getClient(),
|
|
47
|
-
filters: {},
|
|
48
|
-
filtersLogicalOperator: 'and',
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
constructor(props: Props) {
|
|
52
|
-
this.props = {...WidgetSource.defaultProps, ...props};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Subclasses of {@link WidgetRemoteSource} must implement this method, calling
|
|
57
|
-
* {@link WidgetRemoteSource.prototype._getModelSource} for common source
|
|
58
|
-
* properties, and adding additional required properties including 'type' and
|
|
59
|
-
* 'data'.
|
|
60
|
-
*/
|
|
61
|
-
protected abstract getModelSource(owner: string | undefined): ModelSource;
|
|
62
|
-
|
|
63
|
-
protected _getModelSource(
|
|
64
|
-
owner?: string
|
|
65
|
-
): Omit<ModelSource, 'type' | 'data'> {
|
|
66
|
-
const props = this.props;
|
|
67
|
-
return {
|
|
68
|
-
apiVersion: props.apiVersion as ApiVersion,
|
|
69
|
-
apiBaseUrl: props.apiBaseUrl as string,
|
|
70
|
-
clientId: props.clientId as string,
|
|
71
|
-
accessToken: props.accessToken,
|
|
72
|
-
connectionName: props.connectionName,
|
|
73
|
-
filters: getApplicableFilters(owner, props.filters),
|
|
74
|
-
filtersLogicalOperator: props.filtersLogicalOperator,
|
|
75
|
-
spatialDataType: props.spatialDataType,
|
|
76
|
-
spatialDataColumn: props.spatialDataColumn,
|
|
77
|
-
dataResolution: (props as Partial<AggregationOptions>).dataResolution,
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
protected _getSpatialFiltersResolution(
|
|
82
|
-
source: Omit<ModelSource, 'type' | 'data'>,
|
|
83
|
-
spatialFilter?: SpatialFilter,
|
|
84
|
-
referenceViewState?: ViewState
|
|
85
|
-
): number | undefined {
|
|
86
|
-
// spatialFiltersResolution applies only to spatial index sources.
|
|
87
|
-
if (!spatialFilter || source.spatialDataType === 'geo') {
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (!referenceViewState) {
|
|
92
|
-
throw new Error(
|
|
93
|
-
'Missing required option, "spatialIndexReferenceViewState".'
|
|
94
|
-
);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return getSpatialFiltersResolution(source, referenceViewState);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Returns a list of labeled datapoints for categorical data. Suitable for
|
|
102
|
-
* charts including grouped bar charts, pie charts, and tree charts.
|
|
103
|
-
*/
|
|
104
|
-
abstract getCategories(
|
|
105
|
-
options: CategoryRequestOptions
|
|
106
|
-
): Promise<CategoryResponse>;
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Given a list of feature IDs (as found in `_carto_feature_id`) returns all
|
|
110
|
-
* matching features. In datasets containing features with duplicate geometries,
|
|
111
|
-
* feature IDs may be duplicated (IDs are a hash of geometry) and so more
|
|
112
|
-
* results may be returned than IDs in the request.
|
|
113
|
-
* @internal
|
|
114
|
-
* @experimental
|
|
115
|
-
*/
|
|
116
|
-
abstract getFeatures(
|
|
117
|
-
options: FeaturesRequestOptions
|
|
118
|
-
): Promise<FeaturesResponse>;
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Returns a scalar numerical statistic over all matching data. Suitable
|
|
122
|
-
* for 'headline' or 'scorecard' figures such as counts and sums.
|
|
123
|
-
*/
|
|
124
|
-
abstract getFormula(options: FormulaRequestOptions): Promise<FormulaResponse>;
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Returns a list of labeled datapoints for 'bins' of data defined as ticks
|
|
128
|
-
* over a numerical range. Suitable for histogram charts.
|
|
129
|
-
*/
|
|
130
|
-
abstract getHistogram(
|
|
131
|
-
options: HistogramRequestOptions
|
|
132
|
-
): Promise<HistogramResponse>;
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Returns a range (min and max) for a numerical column of matching rows.
|
|
136
|
-
* Suitable for displaying certain 'headline' or 'scorecard' statistics,
|
|
137
|
-
* or rendering a range slider UI for filtering.
|
|
138
|
-
*/
|
|
139
|
-
abstract getRange(options: RangeRequestOptions): Promise<RangeResponse>;
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Returns a list of bivariate datapoints defined as numerical 'x' and 'y'
|
|
143
|
-
* values. Suitable for rendering scatter plots.
|
|
144
|
-
*/
|
|
145
|
-
abstract getScatter(options: ScatterRequestOptions): Promise<ScatterResponse>;
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Returns a list of arbitrary data rows, with support for pagination and
|
|
149
|
-
* sorting. Suitable for displaying tables and lists.
|
|
150
|
-
*/
|
|
151
|
-
abstract getTable(options: TableRequestOptions): Promise<TableResponse>;
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Returns a series of labeled numerical values, grouped into equally-sized
|
|
155
|
-
* time intervals. Suitable for rendering time series charts.
|
|
156
|
-
*/
|
|
157
|
-
abstract getTimeSeries(
|
|
158
|
-
options: TimeSeriesRequestOptions
|
|
159
|
-
): Promise<TimeSeriesResponse>;
|
|
160
|
-
}
|
|
@@ -1,407 +0,0 @@
|
|
|
1
|
-
import {TilesetSourceOptions} from '../sources/index.js';
|
|
2
|
-
import type {ModelSource} from '../models/index.js';
|
|
3
|
-
import {
|
|
4
|
-
CategoryRequestOptions,
|
|
5
|
-
CategoryResponse,
|
|
6
|
-
FeaturesRequestOptions,
|
|
7
|
-
FeaturesResponse,
|
|
8
|
-
FormulaRequestOptions,
|
|
9
|
-
FormulaResponse,
|
|
10
|
-
HistogramRequestOptions,
|
|
11
|
-
HistogramResponse,
|
|
12
|
-
RangeRequestOptions,
|
|
13
|
-
RangeResponse,
|
|
14
|
-
ScatterRequestOptions,
|
|
15
|
-
ScatterResponse,
|
|
16
|
-
TableRequestOptions,
|
|
17
|
-
TableResponse,
|
|
18
|
-
TimeSeriesRequestOptions,
|
|
19
|
-
TimeSeriesResponse,
|
|
20
|
-
} from './types.js';
|
|
21
|
-
import {InvalidColumnError, getApplicableFilters} from '../utils.js';
|
|
22
|
-
import {TileFormat} from '../constants.js';
|
|
23
|
-
import {SpatialFilter, Tile} from '../types.js';
|
|
24
|
-
import {
|
|
25
|
-
TileFeatureExtractOptions,
|
|
26
|
-
applyFilters,
|
|
27
|
-
geojsonFeatures,
|
|
28
|
-
tileFeatures,
|
|
29
|
-
} from '../filters/index.js';
|
|
30
|
-
import {
|
|
31
|
-
aggregationFunctions,
|
|
32
|
-
applySorting,
|
|
33
|
-
groupValuesByColumn,
|
|
34
|
-
groupValuesByDateColumn,
|
|
35
|
-
histogram,
|
|
36
|
-
scatterPlot,
|
|
37
|
-
} from '../operations/index.js';
|
|
38
|
-
import {FeatureData} from '../types-internal.js';
|
|
39
|
-
import {FeatureCollection} from 'geojson';
|
|
40
|
-
import {SpatialDataType} from '../sources/types.js';
|
|
41
|
-
import {WidgetSource, WidgetSourceProps} from './widget-source.js';
|
|
42
|
-
|
|
43
|
-
// TODO(cleanup): Parameter defaults in source functions and widget API calls are
|
|
44
|
-
// currently duplicated and possibly inconsistent. Consider consolidating and
|
|
45
|
-
// operating on Required<T> objects. See:
|
|
46
|
-
// https://github.com/CartoDB/carto-api-client/issues/39
|
|
47
|
-
|
|
48
|
-
export type WidgetTilesetSourceProps = WidgetSourceProps &
|
|
49
|
-
Omit<TilesetSourceOptions, 'filters'> & {
|
|
50
|
-
tileFormat: TileFormat;
|
|
51
|
-
spatialDataType: SpatialDataType;
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
export type WidgetTilesetSourceResult = {widgetSource: WidgetTilesetSource};
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Source for Widget API requests on a data source defined by a tileset.
|
|
58
|
-
*
|
|
59
|
-
* Generally not intended to be constructed directly. Instead, call
|
|
60
|
-
* {@link vectorTilesetSource}, {@link h3TilesetSource}, or {@link quadbinTilesetSource},
|
|
61
|
-
* which can be shared with map layers. Sources contain a `widgetSource`
|
|
62
|
-
* property, for use by widget implementations.
|
|
63
|
-
*
|
|
64
|
-
* Example:
|
|
65
|
-
*
|
|
66
|
-
* ```javascript
|
|
67
|
-
* import { vectorTilesetSource } from '@carto/api-client';
|
|
68
|
-
*
|
|
69
|
-
* const data = vectorTilesetSource({
|
|
70
|
-
* accessToken: '••••',
|
|
71
|
-
* connectionName: 'carto_dw',
|
|
72
|
-
* tableName: 'carto-demo-data.demo_rasters.my_tileset_source'
|
|
73
|
-
* });
|
|
74
|
-
*
|
|
75
|
-
* const { widgetSource } = await data;
|
|
76
|
-
* ```
|
|
77
|
-
*/
|
|
78
|
-
export class WidgetTilesetSource extends WidgetSource<WidgetTilesetSourceProps> {
|
|
79
|
-
private _tiles: Tile[] = [];
|
|
80
|
-
private _features: FeatureData[] = [];
|
|
81
|
-
|
|
82
|
-
protected override getModelSource(owner: string): ModelSource {
|
|
83
|
-
return {
|
|
84
|
-
...super._getModelSource(owner),
|
|
85
|
-
type: 'tileset',
|
|
86
|
-
data: this.props.tableName,
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Loads features as a list of tiles (typically provided by deck.gl).
|
|
92
|
-
* After tiles are loaded, {@link extractTileFeatures} must be called
|
|
93
|
-
* before computing statistics on the tiles.
|
|
94
|
-
*/
|
|
95
|
-
loadTiles(tiles: unknown[]) {
|
|
96
|
-
this._tiles = tiles as Tile[];
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Extracts feature data from tiles previously loaded with {@link loadTiles}.
|
|
101
|
-
* Must be called before computing statistics on tiles.
|
|
102
|
-
*/
|
|
103
|
-
extractTileFeatures({
|
|
104
|
-
spatialFilter,
|
|
105
|
-
uniqueIdProperty,
|
|
106
|
-
options,
|
|
107
|
-
}: {
|
|
108
|
-
spatialFilter: SpatialFilter;
|
|
109
|
-
// TODO(cleanup): As an optional property, 'uniqueIdProperty' will be easy to forget.
|
|
110
|
-
// Would it be better to configure it on the source function, rather than separately
|
|
111
|
-
// on the layer and in 'loadTiles()'?
|
|
112
|
-
uniqueIdProperty?: string;
|
|
113
|
-
options?: TileFeatureExtractOptions;
|
|
114
|
-
}) {
|
|
115
|
-
this._features = tileFeatures({
|
|
116
|
-
tiles: this._tiles,
|
|
117
|
-
options,
|
|
118
|
-
spatialFilter,
|
|
119
|
-
uniqueIdProperty,
|
|
120
|
-
tileFormat: this.props.tileFormat,
|
|
121
|
-
spatialDataColumn: this.props.spatialDataColumn,
|
|
122
|
-
spatialDataType: this.props.spatialDataType,
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/** Loads features as GeoJSON (used for testing). */
|
|
127
|
-
loadGeoJSON({
|
|
128
|
-
geojson,
|
|
129
|
-
spatialFilter,
|
|
130
|
-
uniqueIdProperty,
|
|
131
|
-
}: {
|
|
132
|
-
geojson: FeatureCollection;
|
|
133
|
-
spatialFilter: SpatialFilter;
|
|
134
|
-
uniqueIdProperty?: string;
|
|
135
|
-
}) {
|
|
136
|
-
this._features = geojsonFeatures({
|
|
137
|
-
geojson,
|
|
138
|
-
spatialFilter,
|
|
139
|
-
uniqueIdProperty,
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
override async getFeatures(
|
|
144
|
-
options: FeaturesRequestOptions
|
|
145
|
-
): Promise<FeaturesResponse> {
|
|
146
|
-
throw new Error('getFeatures not supported for tilesets');
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
async getFormula({
|
|
150
|
-
column = '*',
|
|
151
|
-
operation = 'count',
|
|
152
|
-
joinOperation,
|
|
153
|
-
filterOwner,
|
|
154
|
-
}: FormulaRequestOptions): Promise<FormulaResponse> {
|
|
155
|
-
if (operation === 'custom') {
|
|
156
|
-
throw new Error('Custom aggregation not supported for tilesets');
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
if (!this._features.length) {
|
|
160
|
-
return {value: null};
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// Column is required except when operation is 'count'.
|
|
164
|
-
if ((column && column !== '*') || operation !== 'count') {
|
|
165
|
-
assertColumn(this._features, column);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const filteredFeatures = this._getFilteredFeatures(filterOwner);
|
|
169
|
-
|
|
170
|
-
if (filteredFeatures.length === 0 && operation !== 'count') {
|
|
171
|
-
return {value: null};
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const targetOperation = aggregationFunctions[operation];
|
|
175
|
-
return {
|
|
176
|
-
value: targetOperation(
|
|
177
|
-
filteredFeatures as FeatureData[],
|
|
178
|
-
column,
|
|
179
|
-
joinOperation
|
|
180
|
-
),
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
override async getHistogram({
|
|
185
|
-
operation = 'count',
|
|
186
|
-
ticks,
|
|
187
|
-
column,
|
|
188
|
-
joinOperation,
|
|
189
|
-
filterOwner,
|
|
190
|
-
}: HistogramRequestOptions): Promise<HistogramResponse> {
|
|
191
|
-
if (!this._features.length) {
|
|
192
|
-
return [];
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const filteredFeatures = this._getFilteredFeatures(filterOwner);
|
|
196
|
-
|
|
197
|
-
assertColumn(this._features, column);
|
|
198
|
-
|
|
199
|
-
return histogram({
|
|
200
|
-
data: filteredFeatures,
|
|
201
|
-
valuesColumns: normalizeColumns(column),
|
|
202
|
-
joinOperation,
|
|
203
|
-
ticks,
|
|
204
|
-
operation,
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
override async getCategories({
|
|
209
|
-
column,
|
|
210
|
-
operation = 'count',
|
|
211
|
-
operationColumn,
|
|
212
|
-
joinOperation,
|
|
213
|
-
filterOwner,
|
|
214
|
-
}: CategoryRequestOptions): Promise<CategoryResponse> {
|
|
215
|
-
if (!this._features.length) {
|
|
216
|
-
return [];
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
const filteredFeatures = this._getFilteredFeatures(filterOwner);
|
|
220
|
-
|
|
221
|
-
assertColumn(this._features, column as string, operationColumn as string);
|
|
222
|
-
|
|
223
|
-
const groups = groupValuesByColumn({
|
|
224
|
-
data: filteredFeatures,
|
|
225
|
-
valuesColumns: normalizeColumns(operationColumn || column),
|
|
226
|
-
joinOperation,
|
|
227
|
-
keysColumn: column,
|
|
228
|
-
operation,
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
return groups || [];
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
override async getScatter({
|
|
235
|
-
xAxisColumn,
|
|
236
|
-
yAxisColumn,
|
|
237
|
-
xAxisJoinOperation,
|
|
238
|
-
yAxisJoinOperation,
|
|
239
|
-
filterOwner,
|
|
240
|
-
}: ScatterRequestOptions): Promise<ScatterResponse> {
|
|
241
|
-
if (!this._features.length) {
|
|
242
|
-
return [];
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
const filteredFeatures = this._getFilteredFeatures(filterOwner);
|
|
246
|
-
|
|
247
|
-
assertColumn(this._features, xAxisColumn, yAxisColumn);
|
|
248
|
-
|
|
249
|
-
return scatterPlot({
|
|
250
|
-
data: filteredFeatures,
|
|
251
|
-
xAxisColumns: normalizeColumns(xAxisColumn),
|
|
252
|
-
xAxisJoinOperation,
|
|
253
|
-
yAxisColumns: normalizeColumns(yAxisColumn),
|
|
254
|
-
yAxisJoinOperation,
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
override async getTable(
|
|
259
|
-
options: TableRequestOptions
|
|
260
|
-
): Promise<TableResponse> {
|
|
261
|
-
const {filterOwner, spatialFilter, abortController, ...params} = options;
|
|
262
|
-
const {
|
|
263
|
-
columns,
|
|
264
|
-
searchFilterColumn,
|
|
265
|
-
searchFilterText,
|
|
266
|
-
sortBy,
|
|
267
|
-
sortDirection,
|
|
268
|
-
sortByColumnType,
|
|
269
|
-
offset = 0,
|
|
270
|
-
limit = 10,
|
|
271
|
-
} = params;
|
|
272
|
-
|
|
273
|
-
if (!this._features.length) {
|
|
274
|
-
return {rows: [], totalCount: 0};
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// Filter.
|
|
278
|
-
let filteredFeatures = this._getFilteredFeatures(filterOwner);
|
|
279
|
-
|
|
280
|
-
// Search.
|
|
281
|
-
// TODO: Could we get the same behavior by applying filters in loadTiles()?
|
|
282
|
-
if (searchFilterColumn && searchFilterText) {
|
|
283
|
-
filteredFeatures = filteredFeatures.filter(
|
|
284
|
-
(row) =>
|
|
285
|
-
row[searchFilterColumn] &&
|
|
286
|
-
String(row[searchFilterColumn])
|
|
287
|
-
.toLowerCase()
|
|
288
|
-
.includes(String(searchFilterText).toLowerCase())
|
|
289
|
-
);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
// Sort.
|
|
293
|
-
let rows = applySorting(filteredFeatures, {
|
|
294
|
-
sortBy,
|
|
295
|
-
sortByDirection: sortDirection,
|
|
296
|
-
sortByColumnType,
|
|
297
|
-
});
|
|
298
|
-
const totalCount = rows.length;
|
|
299
|
-
|
|
300
|
-
// Offset and limit.
|
|
301
|
-
rows = rows.slice(
|
|
302
|
-
Math.min(offset, totalCount),
|
|
303
|
-
Math.min(offset + limit, totalCount)
|
|
304
|
-
);
|
|
305
|
-
|
|
306
|
-
// Select columns.
|
|
307
|
-
rows = rows.map((srcRow: FeatureData) => {
|
|
308
|
-
const dstRow: FeatureData = {};
|
|
309
|
-
for (const column of columns) {
|
|
310
|
-
dstRow[column] = srcRow[column];
|
|
311
|
-
}
|
|
312
|
-
return dstRow;
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
return {rows, totalCount} as TableResponse;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
override async getTimeSeries({
|
|
319
|
-
column,
|
|
320
|
-
stepSize,
|
|
321
|
-
operation,
|
|
322
|
-
operationColumn,
|
|
323
|
-
joinOperation,
|
|
324
|
-
filterOwner,
|
|
325
|
-
}: TimeSeriesRequestOptions): Promise<TimeSeriesResponse> {
|
|
326
|
-
if (!this._features.length) {
|
|
327
|
-
return {rows: []};
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
const filteredFeatures = this._getFilteredFeatures(filterOwner);
|
|
331
|
-
|
|
332
|
-
assertColumn(this._features, column as string, operationColumn as string);
|
|
333
|
-
|
|
334
|
-
const rows =
|
|
335
|
-
groupValuesByDateColumn({
|
|
336
|
-
data: filteredFeatures,
|
|
337
|
-
valuesColumns: normalizeColumns(operationColumn || column),
|
|
338
|
-
keysColumn: column,
|
|
339
|
-
groupType: stepSize,
|
|
340
|
-
operation,
|
|
341
|
-
joinOperation,
|
|
342
|
-
}) || [];
|
|
343
|
-
|
|
344
|
-
return {rows};
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
override async getRange({
|
|
348
|
-
column,
|
|
349
|
-
filterOwner,
|
|
350
|
-
}: RangeRequestOptions): Promise<RangeResponse> {
|
|
351
|
-
if (!this._features.length) {
|
|
352
|
-
// TODO: Is this the only nullable response in the Widgets API? If so,
|
|
353
|
-
// can we do something more consistent?
|
|
354
|
-
return null;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
assertColumn(this._features, column);
|
|
358
|
-
|
|
359
|
-
const filteredFeatures = this._getFilteredFeatures(filterOwner);
|
|
360
|
-
return {
|
|
361
|
-
min: aggregationFunctions.min(filteredFeatures, column),
|
|
362
|
-
max: aggregationFunctions.max(filteredFeatures, column),
|
|
363
|
-
};
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
/****************************************************************************
|
|
367
|
-
* INTERNAL
|
|
368
|
-
*/
|
|
369
|
-
|
|
370
|
-
private _getFilteredFeatures(filterOwner: string | undefined): FeatureData[] {
|
|
371
|
-
return applyFilters(
|
|
372
|
-
this._features,
|
|
373
|
-
getApplicableFilters(filterOwner, this.props.filters),
|
|
374
|
-
this.props.filtersLogicalOperator || 'and'
|
|
375
|
-
);
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
function assertColumn(
|
|
380
|
-
features: FeatureData[],
|
|
381
|
-
...columnArgs: string[] | string[][]
|
|
382
|
-
) {
|
|
383
|
-
// TODO(cleanup): Can drop support for multiple column shapes here?
|
|
384
|
-
|
|
385
|
-
// Due to the multiple column shape, we normalise it as an array with normalizeColumns
|
|
386
|
-
const columns = Array.from(new Set(columnArgs.map(normalizeColumns).flat()));
|
|
387
|
-
|
|
388
|
-
const featureKeys = Object.keys(features[0]);
|
|
389
|
-
|
|
390
|
-
const invalidColumns = columns.filter(
|
|
391
|
-
(column) => !featureKeys.includes(column)
|
|
392
|
-
);
|
|
393
|
-
|
|
394
|
-
if (invalidColumns.length) {
|
|
395
|
-
throw new InvalidColumnError(
|
|
396
|
-
`Missing column(s): ${invalidColumns.join(', ')}`
|
|
397
|
-
);
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
function normalizeColumns(columns: string | string[]): string[] {
|
|
402
|
-
return Array.isArray(columns)
|
|
403
|
-
? columns
|
|
404
|
-
: typeof columns === 'string'
|
|
405
|
-
? [columns]
|
|
406
|
-
: [];
|
|
407
|
-
}
|