@carto/api-client 0.5.0-alpha.11 → 0.5.0-alpha.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/api-client.cjs +217 -485
- package/build/api-client.cjs.map +1 -1
- package/build/api-client.d.cts +72 -44
- package/build/api-client.d.ts +72 -44
- package/build/api-client.js +216 -477
- package/build/api-client.js.map +1 -1
- package/build/worker.js +110 -389
- package/build/worker.js.map +1 -1
- package/package.json +23 -22
- package/src/deck/get-data-filter-extension-props.ts +27 -9
- package/src/filters/tileFeatures.ts +26 -10
- package/src/filters/tileFeaturesRaster.ts +122 -0
- package/src/sources/raster-source.ts +18 -5
- package/src/sources/types.ts +14 -2
- package/src/types.ts +6 -2
- package/src/widget-sources/index.ts +1 -0
- package/src/widget-sources/widget-raster-source.ts +14 -0
- package/src/widget-sources/widget-tileset-source-impl.ts +13 -16
- package/src/widget-sources/widget-tileset-source.ts +22 -10
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"homepage": "https://github.com/CartoDB/carto-api-client#readme",
|
|
9
9
|
"author": "Don McCurdy <donmccurdy@carto.com>",
|
|
10
10
|
"packageManager": "yarn@4.3.1",
|
|
11
|
-
"version": "0.5.0-alpha.
|
|
11
|
+
"version": "0.5.0-alpha.14",
|
|
12
12
|
"license": "MIT",
|
|
13
13
|
"publishConfig": {
|
|
14
14
|
"access": "public"
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"format:check": "prettier \"**/*.{cjs,html,js,json,md,ts}\" --check",
|
|
50
50
|
"clean": "rimraf build/*",
|
|
51
51
|
"postversion": "yarn postversion:check && yarn postversion:commit && yarn postversion:push",
|
|
52
|
-
"postversion:check": "yarn lint && yarn test",
|
|
52
|
+
"postversion:check": "yarn lint && yarn format:check && yarn test",
|
|
53
53
|
"postversion:commit": "node scripts/postversion-commit.js",
|
|
54
54
|
"postversion:push": "git push && git push --tags",
|
|
55
55
|
"prepublish": "yarn lint && yarn test",
|
|
@@ -73,46 +73,47 @@
|
|
|
73
73
|
"@turf/invariant": "^7.2.0",
|
|
74
74
|
"@turf/union": "^7.2.0",
|
|
75
75
|
"@types/geojson": "^7946.0.16",
|
|
76
|
-
"h3-js": "4.1.0"
|
|
76
|
+
"h3-js": "4.1.0",
|
|
77
|
+
"quadbin": "^0.4.0-alpha.2"
|
|
77
78
|
},
|
|
78
79
|
"devDependencies": {
|
|
79
|
-
"@deck.gl/aggregation-layers": "~9.1.
|
|
80
|
-
"@deck.gl/carto": "~9.1.
|
|
81
|
-
"@deck.gl/core": "~9.1.
|
|
82
|
-
"@deck.gl/extensions": "~9.1.
|
|
83
|
-
"@deck.gl/geo-layers": "~9.1.
|
|
84
|
-
"@deck.gl/layers": "~9.1.
|
|
85
|
-
"@deck.gl/mesh-layers": "~9.1.
|
|
86
|
-
"@eslint/js": "^9.
|
|
80
|
+
"@deck.gl/aggregation-layers": "~9.1.4",
|
|
81
|
+
"@deck.gl/carto": "~9.1.4",
|
|
82
|
+
"@deck.gl/core": "~9.1.4",
|
|
83
|
+
"@deck.gl/extensions": "~9.1.4",
|
|
84
|
+
"@deck.gl/geo-layers": "~9.1.4",
|
|
85
|
+
"@deck.gl/layers": "~9.1.4",
|
|
86
|
+
"@deck.gl/mesh-layers": "~9.1.4",
|
|
87
|
+
"@eslint/js": "^9.21.0",
|
|
87
88
|
"@lit/react": "^1.0.7",
|
|
88
89
|
"@lit/task": "^1.0.2",
|
|
89
90
|
"@loaders.gl/core": "^4.3.3",
|
|
90
|
-
"@luma.gl/core": "~9.1.
|
|
91
|
-
"@luma.gl/engine": "~9.1.
|
|
92
|
-
"@luma.gl/shadertools": "~9.1.
|
|
91
|
+
"@luma.gl/core": "~9.1.4",
|
|
92
|
+
"@luma.gl/engine": "~9.1.4",
|
|
93
|
+
"@luma.gl/shadertools": "~9.1.4",
|
|
93
94
|
"@turf/buffer": "^7.2.0",
|
|
94
95
|
"@turf/random": "^7.2.0",
|
|
95
96
|
"@types/json-schema": "^7.0.15",
|
|
96
97
|
"@types/react": "^18.3.18",
|
|
97
98
|
"@types/semver": "^7.5.8",
|
|
98
|
-
"@vitest/coverage-istanbul": "^3.0.
|
|
99
|
+
"@vitest/coverage-istanbul": "^3.0.7",
|
|
99
100
|
"@webcomponents/webcomponentsjs": "^2.8.0",
|
|
100
101
|
"concurrently": "^9.1.2",
|
|
101
102
|
"echarts": "^5.6.0",
|
|
102
|
-
"eslint": "^9.
|
|
103
|
+
"eslint": "^9.21.0",
|
|
103
104
|
"lit": "^3.2.1",
|
|
104
105
|
"lit-analyzer": "^2.0.3",
|
|
105
|
-
"maplibre-gl": "^5.
|
|
106
|
-
"prettier": "^3.
|
|
106
|
+
"maplibre-gl": "^5.2.0",
|
|
107
|
+
"prettier": "^3.5.3",
|
|
107
108
|
"rimraf": "^6.0.1",
|
|
108
109
|
"semver": "^7.7.1",
|
|
109
110
|
"thenby": "^1.3.4",
|
|
110
111
|
"tinybench": "^3.1.1",
|
|
111
112
|
"tsup": "^8.3.6",
|
|
112
|
-
"typescript": "~5.
|
|
113
|
-
"typescript-eslint": "^8.
|
|
114
|
-
"vite": "^6.
|
|
115
|
-
"vitest": "3.0.
|
|
113
|
+
"typescript": "~5.8.2",
|
|
114
|
+
"typescript-eslint": "^8.26.0",
|
|
115
|
+
"vite": "^6.2.0",
|
|
116
|
+
"vitest": "3.0.7"
|
|
116
117
|
},
|
|
117
118
|
"stableVersion": "0.4.6"
|
|
118
119
|
}
|
|
@@ -8,6 +8,16 @@ type TimeFilter = Filters['string'][FilterType.TIME] & {
|
|
|
8
8
|
params?: {offsetBy?: number};
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* deck.gl's DataFilterExtension supports GPU filtering with 1–4 values. We
|
|
13
|
+
* allocate filters[0] to generic filters and filters[1] to time filters.
|
|
14
|
+
*
|
|
15
|
+
* getFilterValue() _must_ return an array of the same size as the filterSize
|
|
16
|
+
* used to initialize the DataFilterExtension. We document that users must use
|
|
17
|
+
* filterSize=4 for compatibility with @link {getDataFilterExtensionProps}.
|
|
18
|
+
*/
|
|
19
|
+
const DEFAULT_FILTER_SIZE = 4;
|
|
20
|
+
|
|
11
21
|
/** @experimental Prefer type definition from deck.gl. */
|
|
12
22
|
export type _DataFilterExtensionProps = {
|
|
13
23
|
filterRange: number[][];
|
|
@@ -17,22 +27,30 @@ export type _DataFilterExtensionProps = {
|
|
|
17
27
|
|
|
18
28
|
/**
|
|
19
29
|
* Creates props for DataFilterExtension, from `@deck.gl/extensions`, given
|
|
20
|
-
* a set of filters.
|
|
30
|
+
* a set of filters. Requires that DataFilterExtension is initialized with
|
|
31
|
+
* filterSize=4, where the CARTO filters will occupy the first two slots.
|
|
32
|
+
*
|
|
33
|
+
* @example To create a deck.gl layer with GPU data filtering:
|
|
34
|
+
* ```typescript
|
|
35
|
+
* import {DataFilterExtension} from '@deck.gl/extensions';
|
|
36
|
+
* import {VectorTileLayer} from '@deck.gl/layers';
|
|
37
|
+
* import {getDataFilterExtensionProps} from '@carto/api-client';
|
|
21
38
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
39
|
+
* const layer = new VectorTileLayer({
|
|
40
|
+
* data: data,
|
|
41
|
+
* extensions: [new DataFilterExtension({filterSize: 4})],
|
|
42
|
+
* ...getDataFilterExtensionProps(filters),
|
|
43
|
+
* });
|
|
44
|
+
* ```
|
|
25
45
|
*/
|
|
26
46
|
export function getDataFilterExtensionProps(
|
|
27
47
|
filters: Filters,
|
|
28
|
-
filtersLogicalOperator?: FilterLogicalOperator
|
|
29
|
-
filterSize?: 0 | 1 | 2 | 3 | 4
|
|
48
|
+
filtersLogicalOperator?: FilterLogicalOperator
|
|
30
49
|
): _DataFilterExtensionProps {
|
|
31
|
-
filterSize ??= 4;
|
|
32
50
|
const {filtersWithoutTimeType, timeColumn, timeFilter} =
|
|
33
51
|
getFiltersByType(filters);
|
|
34
52
|
return {
|
|
35
|
-
filterRange: getFilterRange(timeFilter,
|
|
53
|
+
filterRange: getFilterRange(timeFilter, DEFAULT_FILTER_SIZE),
|
|
36
54
|
updateTriggers: getUpdateTriggers(
|
|
37
55
|
filtersWithoutTimeType,
|
|
38
56
|
timeColumn,
|
|
@@ -42,7 +60,7 @@ export function getDataFilterExtensionProps(
|
|
|
42
60
|
filtersWithoutTimeType,
|
|
43
61
|
timeColumn,
|
|
44
62
|
timeFilter,
|
|
45
|
-
|
|
63
|
+
DEFAULT_FILTER_SIZE,
|
|
46
64
|
filtersLogicalOperator
|
|
47
65
|
),
|
|
48
66
|
};
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import {SpatialFilter, SpatialIndexTile, Tile} from '../types.js';
|
|
1
|
+
import {RasterTile, SpatialFilter, SpatialIndexTile, Tile} from '../types.js';
|
|
2
2
|
import {tileFeaturesGeometries} from './tileFeaturesGeometries.js';
|
|
3
3
|
import {tileFeaturesSpatialIndex} from './tileFeaturesSpatialIndex.js';
|
|
4
4
|
import {TileFormat} from '../constants.js';
|
|
5
5
|
import {DEFAULT_GEO_COLUMN} from '../constants-internal.js';
|
|
6
6
|
import {FeatureData} from '../types-internal.js';
|
|
7
|
-
import {SpatialDataType} from '../sources/types.js';
|
|
7
|
+
import {RasterMetadata, SpatialDataType} from '../sources/types.js';
|
|
8
|
+
import {isRasterTile, tileFeaturesRaster} from './tileFeaturesRaster.js';
|
|
9
|
+
import {assert} from '../utils.js';
|
|
8
10
|
|
|
9
11
|
/** @privateRemarks Source: @carto/react-core */
|
|
10
12
|
export type TileFeatures = {
|
|
@@ -14,6 +16,7 @@ export type TileFeatures = {
|
|
|
14
16
|
spatialDataColumn?: string;
|
|
15
17
|
spatialFilter: SpatialFilter;
|
|
16
18
|
uniqueIdProperty?: string;
|
|
19
|
+
rasterMetadata?: RasterMetadata;
|
|
17
20
|
options?: TileFeatureExtractOptions;
|
|
18
21
|
};
|
|
19
22
|
|
|
@@ -31,21 +34,34 @@ export function tileFeatures({
|
|
|
31
34
|
tileFormat,
|
|
32
35
|
spatialDataColumn = DEFAULT_GEO_COLUMN,
|
|
33
36
|
spatialDataType,
|
|
37
|
+
rasterMetadata,
|
|
34
38
|
options = {},
|
|
35
39
|
}: TileFeatures): FeatureData[] {
|
|
36
|
-
if (spatialDataType
|
|
37
|
-
return
|
|
38
|
-
tiles
|
|
40
|
+
if (spatialDataType === 'geo') {
|
|
41
|
+
return tileFeaturesGeometries({
|
|
42
|
+
tiles,
|
|
43
|
+
tileFormat,
|
|
44
|
+
spatialFilter,
|
|
45
|
+
uniqueIdProperty,
|
|
46
|
+
options,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (tiles.some(isRasterTile)) {
|
|
51
|
+
assert(rasterMetadata, 'Missing raster metadata');
|
|
52
|
+
return tileFeaturesRaster({
|
|
53
|
+
tiles: tiles as RasterTile[],
|
|
39
54
|
spatialFilter,
|
|
40
55
|
spatialDataColumn,
|
|
41
56
|
spatialDataType,
|
|
57
|
+
rasterMetadata,
|
|
42
58
|
});
|
|
43
59
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
60
|
+
|
|
61
|
+
return tileFeaturesSpatialIndex({
|
|
62
|
+
tiles: tiles as SpatialIndexTile[],
|
|
47
63
|
spatialFilter,
|
|
48
|
-
|
|
49
|
-
|
|
64
|
+
spatialDataColumn,
|
|
65
|
+
spatialDataType,
|
|
50
66
|
});
|
|
51
67
|
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cellToChildren as _cellToChildren,
|
|
3
|
+
cellToTile,
|
|
4
|
+
geometryToCells,
|
|
5
|
+
getResolution,
|
|
6
|
+
} from 'quadbin';
|
|
7
|
+
import {RasterTile, SpatialFilter, Tile} from '../types.js';
|
|
8
|
+
import {FeatureData} from '../types-internal.js';
|
|
9
|
+
import {
|
|
10
|
+
RasterMetadata,
|
|
11
|
+
RasterMetadataBand,
|
|
12
|
+
SpatialDataType,
|
|
13
|
+
} from '../sources/types.js';
|
|
14
|
+
|
|
15
|
+
export type TileFeaturesRasterOptions = {
|
|
16
|
+
tiles: RasterTile[];
|
|
17
|
+
spatialFilter: SpatialFilter;
|
|
18
|
+
spatialDataColumn: string;
|
|
19
|
+
spatialDataType: SpatialDataType;
|
|
20
|
+
rasterMetadata: RasterMetadata;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export function tileFeaturesRaster({
|
|
24
|
+
tiles,
|
|
25
|
+
...options
|
|
26
|
+
}: TileFeaturesRasterOptions): FeatureData[] {
|
|
27
|
+
// Cache band metadata for faster lookup while iterating over pixels.
|
|
28
|
+
const metadataByBand: Record<string, RasterMetadataBand & {nodata: number}> =
|
|
29
|
+
{};
|
|
30
|
+
for (const band of options.rasterMetadata.bands) {
|
|
31
|
+
// TODO(cleanup): Remove copy and cast after API is updated to return 'nodata' as a number.
|
|
32
|
+
metadataByBand[band.name] = {...band, nodata: Number(band.nodata)};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Omit empty and invisible tiles for simpler processing and types.
|
|
36
|
+
tiles = tiles.filter(isRasterTileVisible);
|
|
37
|
+
if (tiles.length === 0) return [];
|
|
38
|
+
|
|
39
|
+
// Raster tiles, and all pixels, are quadbin cells. Resolution of a pixel is
|
|
40
|
+
// the resolution of the tile, plus the number of subdivisions. Block size
|
|
41
|
+
// must be square, N x N, where N is a power of two.
|
|
42
|
+
const tileResolution = getResolution(tiles[0].index.q);
|
|
43
|
+
const tileBlockSize = tiles[0].data!.blockSize;
|
|
44
|
+
const cellResolution = tileResolution + BigInt(Math.log2(tileBlockSize));
|
|
45
|
+
|
|
46
|
+
// Compute covering cells for the spatial filter, at same resolution as the
|
|
47
|
+
// raster pixels, to be used as a mask.
|
|
48
|
+
const spatialFilterCells = new Set(
|
|
49
|
+
geometryToCells(options.spatialFilter, cellResolution)
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const data = new Map<bigint, FeatureData>();
|
|
53
|
+
|
|
54
|
+
for (const tile of tiles as Required<RasterTile>[]) {
|
|
55
|
+
const parent = tile.index.q;
|
|
56
|
+
|
|
57
|
+
const children = cellToChildrenSorted(parent, cellResolution);
|
|
58
|
+
|
|
59
|
+
// For each pixel/cell within the spatial filter, create a FeatureData.
|
|
60
|
+
// Order is row-major, starting from NW and ending at SE.
|
|
61
|
+
for (let i = 0; i < children.length; i++) {
|
|
62
|
+
if (!spatialFilterCells.has(children[i])) continue;
|
|
63
|
+
|
|
64
|
+
const cellData: FeatureData = {};
|
|
65
|
+
let cellDataExists = false;
|
|
66
|
+
|
|
67
|
+
for (const band in tile.data.cells.numericProps) {
|
|
68
|
+
const value = tile.data.cells.numericProps[band].value[i];
|
|
69
|
+
const bandMetadata = metadataByBand[band];
|
|
70
|
+
|
|
71
|
+
if (isValidBandValue(value, bandMetadata.nodata)) {
|
|
72
|
+
cellData[band] = tile.data.cells.numericProps[band].value[i];
|
|
73
|
+
cellDataExists = true;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (cellDataExists) {
|
|
78
|
+
data.set(children[i], cellData);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return Array.from(data.values());
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Detects whether a given {@link Tile} is a {@link RasterTile}.
|
|
88
|
+
* @privateRemarks Method of detection is arbitrary, and may be changed.
|
|
89
|
+
*/
|
|
90
|
+
export function isRasterTile(tile: Tile): tile is RasterTile {
|
|
91
|
+
return !!(tile.data as Record<string, unknown>)?.cells;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function isRasterTileVisible(tile: RasterTile): tile is Required<RasterTile> {
|
|
95
|
+
return !!(tile.isVisible && tile.data?.cells?.numericProps);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* For the raster format, children are sorted in row-major order, starting from
|
|
100
|
+
* NW and ending at SE. Order returned by quadbin's cellToChildren() is not
|
|
101
|
+
* defined (and not related to the raster format), so sort explicitly here.
|
|
102
|
+
*/
|
|
103
|
+
function cellToChildrenSorted(parent: bigint, resolution: bigint): bigint[] {
|
|
104
|
+
return _cellToChildren(parent, resolution).sort(
|
|
105
|
+
(cellA: bigint, cellB: bigint) => {
|
|
106
|
+
const tileA = cellToTile(cellA);
|
|
107
|
+
const tileB = cellToTile(cellB);
|
|
108
|
+
if (tileA.y !== tileB.y) {
|
|
109
|
+
return tileA.y > tileB.y ? 1 : -1;
|
|
110
|
+
}
|
|
111
|
+
return tileA.x > tileB.x ? 1 : -1;
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Returns true if the given value is valid (not NaN, not 'nodata')
|
|
118
|
+
* for the given raster band.
|
|
119
|
+
*/
|
|
120
|
+
function isValidBandValue(value: unknown, nodata: number): value is number {
|
|
121
|
+
return Number.isNaN(value) ? false : nodata !== value;
|
|
122
|
+
}
|
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
5
|
import {baseSource} from './base-source.js';
|
|
6
|
+
import {getTileFormat} from '../utils/getTileFormat.js';
|
|
7
|
+
import {
|
|
8
|
+
WidgetRasterSource,
|
|
9
|
+
WidgetRasterSourceResult,
|
|
10
|
+
} from '../widget-sources/index.js';
|
|
11
|
+
|
|
6
12
|
import type {
|
|
7
13
|
FilterOptions,
|
|
8
14
|
SourceOptions,
|
|
@@ -18,7 +24,7 @@ type UrlParameters = {
|
|
|
18
24
|
filters?: Record<string, unknown>;
|
|
19
25
|
};
|
|
20
26
|
|
|
21
|
-
export type RasterSourceResponse = TilejsonResult;
|
|
27
|
+
export type RasterSourceResponse = TilejsonResult & WidgetRasterSourceResult;
|
|
22
28
|
|
|
23
29
|
export const rasterSource = async function (
|
|
24
30
|
options: RasterSourceOptions
|
|
@@ -29,9 +35,16 @@ export const rasterSource = async function (
|
|
|
29
35
|
urlParameters.filters = filters;
|
|
30
36
|
}
|
|
31
37
|
|
|
32
|
-
return baseSource<UrlParameters>(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
return baseSource<UrlParameters>('raster', options, urlParameters).then(
|
|
39
|
+
(result) => ({
|
|
40
|
+
...(result as TilejsonResult),
|
|
41
|
+
widgetSource: new WidgetRasterSource({
|
|
42
|
+
...options,
|
|
43
|
+
tileFormat: getTileFormat(result as TilejsonResult),
|
|
44
|
+
spatialDataColumn: 'quadbin',
|
|
45
|
+
spatialDataType: 'quadbin',
|
|
46
|
+
rasterMetadata: (result as TilejsonResult).raster_metadata!,
|
|
47
|
+
}),
|
|
48
|
+
})
|
|
36
49
|
) as Promise<RasterSourceResponse>;
|
|
37
50
|
};
|
package/src/sources/types.ts
CHANGED
|
@@ -364,8 +364,20 @@ export enum RasterBandColorinterp {
|
|
|
364
364
|
Palette = 'palette',
|
|
365
365
|
}
|
|
366
366
|
|
|
367
|
+
export type RasterBandType =
|
|
368
|
+
| 'uint8'
|
|
369
|
+
| 'int8'
|
|
370
|
+
| 'uint16'
|
|
371
|
+
| 'int16'
|
|
372
|
+
| 'uint32'
|
|
373
|
+
| 'int32'
|
|
374
|
+
| 'uint64'
|
|
375
|
+
| 'int64'
|
|
376
|
+
| 'float32'
|
|
377
|
+
| 'float64';
|
|
378
|
+
|
|
367
379
|
export type RasterMetadataBand = {
|
|
368
|
-
type:
|
|
380
|
+
type: RasterBandType;
|
|
369
381
|
name: string;
|
|
370
382
|
stats: RasterMetadataBandStats;
|
|
371
383
|
/**
|
|
@@ -379,7 +391,7 @@ export type RasterMetadataBand = {
|
|
|
379
391
|
/**
|
|
380
392
|
* Default color mapping for unique values (or if coloprinterp is `palette`)
|
|
381
393
|
*/
|
|
382
|
-
colortable?: Record<string, number
|
|
394
|
+
colortable?: Record<string, [number, number, number, number]>;
|
|
383
395
|
|
|
384
396
|
/**
|
|
385
397
|
* No value representation.
|
package/src/types.ts
CHANGED
|
@@ -28,8 +28,6 @@ export type Viewport = [number, number, number, number];
|
|
|
28
28
|
export type Tile = {
|
|
29
29
|
index: {x: number; y: number; z: number};
|
|
30
30
|
id: string;
|
|
31
|
-
content: unknown;
|
|
32
|
-
zoom: number;
|
|
33
31
|
bbox: {west: number; east: number; north: number; south: number};
|
|
34
32
|
isVisible: boolean;
|
|
35
33
|
data?: BinaryFeatureCollection;
|
|
@@ -40,6 +38,12 @@ export type SpatialIndexTile = Tile & {
|
|
|
40
38
|
data?: (Feature & {id: bigint})[];
|
|
41
39
|
};
|
|
42
40
|
|
|
41
|
+
export type RasterTile = Tile & {
|
|
42
|
+
id: string;
|
|
43
|
+
index: {q: bigint; i: string};
|
|
44
|
+
data?: Raster;
|
|
45
|
+
};
|
|
46
|
+
|
|
43
47
|
/** @privateRemarks Source: @deck.gl/carto */
|
|
44
48
|
export type Raster = {
|
|
45
49
|
blockSize: number;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {RasterMetadata} from '../sources/index.js';
|
|
2
|
+
import {
|
|
3
|
+
WidgetTilesetSource,
|
|
4
|
+
WidgetTilesetSourceProps,
|
|
5
|
+
} from './widget-tileset-source.js';
|
|
6
|
+
|
|
7
|
+
export type WidgetRasterSourceProps = WidgetTilesetSourceProps & {
|
|
8
|
+
rasterMetadata: RasterMetadata;
|
|
9
|
+
spatialDataType: 'quadbin';
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type WidgetRasterSourceResult = {widgetSource: WidgetRasterSource};
|
|
13
|
+
|
|
14
|
+
export class WidgetRasterSource extends WidgetTilesetSource<WidgetRasterSourceProps> {}
|
|
@@ -84,13 +84,10 @@ export class WidgetTilesetSourceImpl extends WidgetSource<WidgetTilesetSourcePro
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
this._features = tileFeatures({
|
|
87
|
-
|
|
88
|
-
tileFormat: this.props.tileFormat,
|
|
87
|
+
...this.props,
|
|
89
88
|
...this._tileFeatureExtractOptions,
|
|
90
|
-
|
|
89
|
+
tiles: this._tiles,
|
|
91
90
|
spatialFilter,
|
|
92
|
-
spatialDataColumn: this.props.spatialDataColumn,
|
|
93
|
-
spatialDataType: this.props.spatialDataType,
|
|
94
91
|
});
|
|
95
92
|
|
|
96
93
|
prevInputs.spatialFilter = spatialFilter;
|
|
@@ -128,15 +125,6 @@ export class WidgetTilesetSourceImpl extends WidgetSource<WidgetTilesetSourcePro
|
|
|
128
125
|
filterOwner,
|
|
129
126
|
spatialFilter,
|
|
130
127
|
}: FormulaRequestOptions): Promise<FormulaResponse> {
|
|
131
|
-
if (operation === 'custom') {
|
|
132
|
-
throw new Error('Custom aggregation not supported for tilesets');
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Column is required except when operation is 'count'.
|
|
136
|
-
if ((column && column !== '*') || operation !== 'count') {
|
|
137
|
-
assertColumn(this._features, column);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
128
|
const filteredFeatures = this._getFilteredFeatures(
|
|
141
129
|
spatialFilter,
|
|
142
130
|
filters,
|
|
@@ -147,6 +135,15 @@ export class WidgetTilesetSourceImpl extends WidgetSource<WidgetTilesetSourcePro
|
|
|
147
135
|
return {value: null};
|
|
148
136
|
}
|
|
149
137
|
|
|
138
|
+
if (operation === 'custom') {
|
|
139
|
+
throw new Error('Custom aggregation not supported for tilesets');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Column is required except when operation is 'count'.
|
|
143
|
+
if ((column && column !== '*') || operation !== 'count') {
|
|
144
|
+
assertColumn(this._features, column);
|
|
145
|
+
}
|
|
146
|
+
|
|
150
147
|
const targetOperation = aggregationFunctions[operation];
|
|
151
148
|
return {
|
|
152
149
|
value: targetOperation(filteredFeatures, column, joinOperation),
|
|
@@ -347,8 +344,6 @@ export class WidgetTilesetSourceImpl extends WidgetSource<WidgetTilesetSourcePro
|
|
|
347
344
|
filterOwner,
|
|
348
345
|
spatialFilter,
|
|
349
346
|
}: RangeRequestOptions): Promise<RangeResponse> {
|
|
350
|
-
assertColumn(this._features, column);
|
|
351
|
-
|
|
352
347
|
const filteredFeatures = this._getFilteredFeatures(
|
|
353
348
|
spatialFilter,
|
|
354
349
|
filters,
|
|
@@ -361,6 +356,8 @@ export class WidgetTilesetSourceImpl extends WidgetSource<WidgetTilesetSourcePro
|
|
|
361
356
|
return null;
|
|
362
357
|
}
|
|
363
358
|
|
|
359
|
+
assertColumn(this._features, column);
|
|
360
|
+
|
|
364
361
|
return {
|
|
365
362
|
min: aggregationFunctions.min(filteredFeatures, column),
|
|
366
363
|
max: aggregationFunctions.max(filteredFeatures, column),
|
|
@@ -55,14 +55,16 @@ export type WidgetTilesetSourceResult = {widgetSource: WidgetTilesetSource};
|
|
|
55
55
|
* const { widgetSource } = await data;
|
|
56
56
|
* ```
|
|
57
57
|
*/
|
|
58
|
-
export class WidgetTilesetSource
|
|
58
|
+
export class WidgetTilesetSource<
|
|
59
|
+
Props extends WidgetTilesetSourceProps = WidgetTilesetSourceProps,
|
|
60
|
+
> extends WidgetSource<Props> {
|
|
59
61
|
protected _localImpl: WidgetTilesetSourceImpl | null = null;
|
|
60
62
|
|
|
61
63
|
protected _workerImpl: Worker | null = null;
|
|
62
64
|
protected _workerEnabled: boolean;
|
|
63
65
|
protected _workerNextRequestId = 1;
|
|
64
66
|
|
|
65
|
-
constructor(props:
|
|
67
|
+
constructor(props: Props) {
|
|
66
68
|
super(props);
|
|
67
69
|
|
|
68
70
|
this._workerEnabled =
|
|
@@ -145,10 +147,9 @@ export class WidgetTilesetSource extends WidgetSource<WidgetTilesetSourceProps>
|
|
|
145
147
|
function onMessage(e: MessageEvent) {
|
|
146
148
|
const response = e.data as WorkerResponse;
|
|
147
149
|
if (response.requestId !== requestId) return;
|
|
150
|
+
if (signal?.aborted) return; // handled by 'abort' listener
|
|
148
151
|
|
|
149
|
-
if (
|
|
150
|
-
reject!(new Error(signal.reason));
|
|
151
|
-
} else if (response.ok) {
|
|
152
|
+
if (response.ok) {
|
|
152
153
|
resolve!(response.result as T);
|
|
153
154
|
} else {
|
|
154
155
|
reject!(new Error(response.error));
|
|
@@ -199,11 +200,22 @@ export class WidgetTilesetSource extends WidgetSource<WidgetTilesetSourceProps>
|
|
|
199
200
|
|
|
200
201
|
const worker = this._getWorker();
|
|
201
202
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
203
|
+
// We cannot pass an instance of Tile2DHeader to a Web Worker, and must
|
|
204
|
+
// extract properties required for widget calculations. Note that the
|
|
205
|
+
// `tile: Tile = {...}` assignment is structured so TS will warn if any
|
|
206
|
+
// types required by the internal 'Tile' type are missing.
|
|
207
|
+
tiles = (tiles as Tile[]).map(
|
|
208
|
+
({id, index, bbox, isVisible, data}: Tile) => {
|
|
209
|
+
const tile: Tile = {
|
|
210
|
+
id,
|
|
211
|
+
index,
|
|
212
|
+
isVisible,
|
|
213
|
+
data,
|
|
214
|
+
bbox,
|
|
215
|
+
};
|
|
216
|
+
return tile;
|
|
217
|
+
}
|
|
218
|
+
);
|
|
207
219
|
|
|
208
220
|
worker.postMessage({
|
|
209
221
|
method: Method.LOAD_TILES,
|