@carto/api-client 0.4.1-alpha.1 → 0.4.2-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
1
  import { Filter, FilterLogicalOperator, MapType, QueryParameters, SpatialFilter } from '../types.js';
2
2
  import { ModelRequestOptions } from './common.js';
3
3
  import { ApiVersion } from '../constants.js';
4
+ import { SpatialDataType, SpatialFilterPolyfillMode } from '../sources/types.js';
4
5
  /** @internalRemarks Source: @carto/react-api */
5
6
  declare const AVAILABLE_MODELS: readonly ["category", "histogram", "formula", "pick", "timeseries", "range", "scatterplot", "table"];
6
7
  export type Model = (typeof AVAILABLE_MODELS)[number];
@@ -14,9 +15,14 @@ export interface ModelSource {
14
15
  data: string;
15
16
  filters?: Record<string, Filter>;
16
17
  filtersLogicalOperator?: FilterLogicalOperator;
17
- geoColumn?: string;
18
18
  spatialFilter?: SpatialFilter;
19
19
  queryParameters?: QueryParameters;
20
+ spatialDataColumn?: string;
21
+ spatialDataType?: SpatialDataType;
22
+ spatialFiltersResolution?: number;
23
+ spatialFiltersMode?: SpatialFilterPolyfillMode;
24
+ /** original resolution of the spatial index data as stored in the DW */
25
+ dataResolution?: number;
20
26
  }
21
27
  /**
22
28
  * Execute a SQL model request.
@@ -38,6 +38,30 @@ export type SourceOptionalOptions = {
38
38
  * @default {@link DEFAULT_MAX_LENGTH_URL}
39
39
  */
40
40
  maxLengthURL?: number;
41
+ /**
42
+ * The column name and the type of geospatial support.
43
+ *
44
+ * If not present, defaults to `'geom'` for generic queries, `'quadbin'` for Quadbin sources and `'h3'` for H3 sources.
45
+ */
46
+ spatialDataColumn?: string;
47
+ /**
48
+ * The type of geospatial support. Defaults to `'geo'`.
49
+ */
50
+ spatialDataType?: SpatialDataType;
51
+ /**
52
+ * Relative resolution of a tile. Higher values increase density and data size. At `tileResolution = 1`, tile geometry is
53
+ * quantized to a 1024x1024 grid. Increasing or decreasing the resolution will increase or decrease the dimensions of
54
+ * the quantization grid proportionately.
55
+ *
56
+ * Supported `tileResolution` values, with corresponding grid sizes:
57
+ *
58
+ * - 0.25: 256x256
59
+ * - 0.5: 512x512
60
+ * - 1: 1024x1024
61
+ * - 2: 2048x2048
62
+ * - 4: 4096x4096
63
+ */
64
+ tileResolution?: TileResolution;
41
65
  /**
42
66
  * By default, local in-memory caching is enabled.
43
67
  */
@@ -73,6 +97,10 @@ export type AggregationOptions = {
73
97
  * @default 6 for quadbin and 4 for h3 sources
74
98
  */
75
99
  aggregationResLevel?: number;
100
+ /**
101
+ * Original resolution of the spatial index data as stored in the DW
102
+ */
103
+ dataResolution?: number;
76
104
  };
77
105
  export type FilterOptions = {
78
106
  /**
@@ -81,28 +109,8 @@ export type FilterOptions = {
81
109
  filters?: Filters;
82
110
  };
83
111
  export type QuerySourceOptions = {
84
- /**
85
- * The column name and the type of geospatial support.
86
- *
87
- * If not present, defaults to `'geom'` for generic queries, `'quadbin'` for Quadbin sources and `'h3'` for H3 sources.
88
- */
89
- spatialDataColumn?: string;
90
- /** SQL query. */
112
+ /** Full SQL query with query paremeter placeholders (if any). */
91
113
  sqlQuery: string;
92
- /**
93
- * Relative resolution of a tile. Higher values increase density and data size. At `tileResolution = 1`, tile geometry is
94
- * quantized to a 1024x1024 grid. Increasing or decreasing the resolution will increase or decrease the dimensions of
95
- * the quantization grid proportionately.
96
- *
97
- * Supported `tileResolution` values, with corresponding grid sizes:
98
- *
99
- * - 0.25: 256x256
100
- * - 0.5: 512x512
101
- * - 1: 1024x1024
102
- * - 2: 2048x2048
103
- * - 4: 4096x4096
104
- */
105
- tileResolution?: TileResolution;
106
114
  /**
107
115
  * Values for named or positional paramteres in the query.
108
116
  *
@@ -134,26 +142,6 @@ export type TableSourceOptions = {
134
142
  * Fully qualified name of table.
135
143
  */
136
144
  tableName: string;
137
- /**
138
- * The column name and the type of geospatial support.
139
- *
140
- * If not present, defaults to `'geom'` for generic tables, `'quadbin'` for Quadbin sources and `'h3'` for H3 sources.
141
- */
142
- spatialDataColumn?: string;
143
- /**
144
- * Relative resolution of a tile. Higher values increase density and data size. At `tileResolution = 1`, tile geometry is
145
- * quantized to a 1024x1024 grid. Increasing or decreasing the resolution will increase or decrease the dimensions of
146
- * the quantization grid proportionately.
147
- *
148
- * Supported `tileResolution` values, with corresponding grid sizes:
149
- *
150
- * - 0.25: 256x256
151
- * - 0.5: 512x512
152
- * - 1: 1024x1024
153
- * - 2: 2048x2048
154
- * - 4: 4096x4096
155
- */
156
- tileResolution?: TileResolution;
157
145
  };
158
146
  export type TilesetSourceOptions = {
159
147
  /**
@@ -170,6 +158,13 @@ export type ColumnsOption = {
170
158
  columns?: string[];
171
159
  };
172
160
  export type SpatialDataType = 'geo' | 'h3' | 'quadbin';
161
+ /**
162
+ * Strategy used for covering spatial filter geometry with spatial indexes.
163
+ * See https://docs.carto.com/data-and-analysis/analytics-toolbox-for-bigquery/sql-reference/quadbin#quadbin_polyfill_mode
164
+ * or https://docs.carto.com/data-and-analysis/analytics-toolbox-for-bigquery/sql-reference/h3#h3_polyfill_mode for more information.
165
+ * @internalRemarks Source: cloud-native maps-api
166
+ * */
167
+ export type SpatialFilterPolyfillMode = 'center' | 'intersects' | 'contains';
173
168
  export type TilejsonMapInstantiation = MapInstantiation & {
174
169
  tilejson: {
175
170
  url: string[];
@@ -0,0 +1,11 @@
1
+ import type { ModelSource } from './models/model';
2
+ import type { AggregationOptions } from './sources/types';
3
+ import type { ViewState } from './widget-sources';
4
+ export declare function getSpatialFiltersResolution({ source, viewState, }: {
5
+ source: Partial<ModelSource & AggregationOptions>;
6
+ viewState?: ViewState;
7
+ }): number | undefined;
8
+ export declare function getHexagonResolution(viewport: {
9
+ zoom: number;
10
+ latitude: number;
11
+ }, tileSize: number): number;
package/build/utils.d.ts CHANGED
@@ -14,7 +14,7 @@ type Row<T> = Record<string, T> | Record<string, T>[] | T[] | T;
14
14
  */
15
15
  export declare function normalizeObjectKeys<T, R extends Row<T>>(el: R): R;
16
16
  /** @internalRemarks Source: @carto/react-core */
17
- export declare function assert(condition: unknown, message: string): void;
17
+ export declare function assert(condition: unknown, message: string): asserts condition;
18
18
  /**
19
19
  * @internalRemarks Source: @carto/react-core
20
20
  * @internal
@@ -1,13 +1,20 @@
1
- import { TileResolution } from '../sources/types';
1
+ import { SpatialFilterPolyfillMode, TileResolution } from '../sources/types';
2
2
  import { GroupDateType, SortColumnType, SortDirection, SpatialFilter } from '../types';
3
3
  /******************************************************************************
4
4
  * WIDGET API REQUESTS
5
5
  */
6
+ export interface ViewState {
7
+ zoom: number;
8
+ latitude: number;
9
+ longitude: number;
10
+ }
6
11
  /** Common options for {@link WidgetBaseSource} requests. */
7
12
  interface BaseRequestOptions {
8
13
  spatialFilter?: SpatialFilter;
14
+ spatialFiltersMode?: SpatialFilterPolyfillMode;
9
15
  abortController?: AbortController;
10
16
  filterOwner?: string;
17
+ viewState?: ViewState;
11
18
  }
12
19
  /** Options for {@link WidgetBaseSource#getCategories}. */
13
20
  export interface CategoryRequestOptions extends BaseRequestOptions {
@@ -5,7 +5,6 @@ import { SourceOptions } from '../sources/index.js';
5
5
  import { ApiVersion } from '../constants.js';
6
6
  export interface WidgetBaseSourceProps extends Omit<SourceOptions, 'filters'> {
7
7
  apiVersion?: ApiVersion;
8
- geoColumn?: string;
9
8
  filters?: Record<string, Filter>;
10
9
  filtersLogicalOperator?: FilterLogicalOperator;
11
10
  }
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "repository": "github:CartoDB/carto-api-client",
5
5
  "author": "Don McCurdy <donmccurdy@carto.com>",
6
6
  "packageManager": "yarn@4.3.1",
7
- "version": "0.4.1-alpha.1",
7
+ "version": "0.4.2-alpha.0",
8
8
  "license": "MIT",
9
9
  "publishConfig": {
10
10
  "access": "public",
package/src/api/query.ts CHANGED
@@ -12,8 +12,7 @@ import {buildQueryUrl} from './endpoints';
12
12
  import {requestWithParameters} from './request-with-parameters';
13
13
  import {APIErrorContext} from './carto-api-error';
14
14
 
15
- export type QueryOptions = SourceOptions &
16
- Omit<QuerySourceOptions, 'spatialDataColumn'>;
15
+ export type QueryOptions = SourceOptions & QuerySourceOptions;
17
16
  type UrlParameters = {q: string; queryParameters?: string};
18
17
 
19
18
  export const query = async function (
@@ -7,9 +7,10 @@ import {
7
7
  SpatialFilter,
8
8
  } from '../types.js';
9
9
  import {$TODO} from '../types-internal.js';
10
- import {assert} from '../utils.js';
10
+ import {assert, isPureObject} from '../utils.js';
11
11
  import {ModelRequestOptions, makeCall} from './common.js';
12
12
  import {ApiVersion} from '../constants.js';
13
+ import {SpatialDataType, SpatialFilterPolyfillMode} from '../sources/types.js';
13
14
 
14
15
  /** @internalRemarks Source: @carto/react-api */
15
16
  const AVAILABLE_MODELS = [
@@ -35,9 +36,14 @@ export interface ModelSource {
35
36
  data: string;
36
37
  filters?: Record<string, Filter>;
37
38
  filtersLogicalOperator?: FilterLogicalOperator;
38
- geoColumn?: string;
39
39
  spatialFilter?: SpatialFilter;
40
40
  queryParameters?: QueryParameters;
41
+ spatialDataColumn?: string;
42
+ spatialDataType?: SpatialDataType;
43
+ spatialFiltersResolution?: number;
44
+ spatialFiltersMode?: SpatialFilterPolyfillMode;
45
+ /** original resolution of the spatial index data as stored in the DW */
46
+ dataResolution?: number;
41
47
  }
42
48
 
43
49
  const {V3} = ApiVersion;
@@ -79,50 +85,51 @@ export function executeModel(props: {
79
85
  data,
80
86
  filters,
81
87
  filtersLogicalOperator = 'and',
82
- geoColumn = DEFAULT_GEO_COLUMN,
88
+ spatialDataType = 'geo',
89
+ spatialFiltersMode = 'intersects',
90
+ spatialFiltersResolution = 0,
83
91
  } = source;
84
92
 
85
- const queryParameters = source.queryParameters
86
- ? JSON.stringify(source.queryParameters)
87
- : '';
88
-
89
- const queryParams: Record<string, string> = {
93
+ const queryParams: Record<string, unknown> = {
90
94
  type,
91
95
  client: clientId,
92
96
  source: data,
93
- params: JSON.stringify(params),
94
- queryParameters,
95
- filters: JSON.stringify(filters),
97
+ params,
98
+ queryParameters: source.queryParameters || '',
99
+ filters,
96
100
  filtersLogicalOperator,
97
101
  };
98
102
 
103
+ const spatialDataColumn = source.spatialDataColumn || DEFAULT_GEO_COLUMN;
104
+
99
105
  // Picking Model API requires 'spatialDataColumn'.
100
106
  if (model === 'pick') {
101
- queryParams.spatialDataColumn = geoColumn;
107
+ queryParams.spatialDataColumn = spatialDataColumn;
102
108
  }
103
109
 
104
- // API supports multiple filters, we apply it only to geoColumn
110
+ // API supports multiple filters, we apply it only to spatialDataColumn
105
111
  const spatialFilters = source.spatialFilter
106
- ? {[geoColumn]: source.spatialFilter}
112
+ ? {[spatialDataColumn]: source.spatialFilter}
107
113
  : undefined;
108
114
 
109
115
  if (spatialFilters) {
110
- queryParams.spatialFilters = JSON.stringify(spatialFilters);
116
+ queryParams.spatialFilters = spatialFilters; // JSON.stringify(spatialFilters);
117
+ queryParams.spatialDataColumn = spatialDataColumn;
118
+ queryParams.spatialDataType = spatialDataType;
119
+ }
120
+
121
+ if (spatialDataType !== 'geo') {
122
+ if (spatialFiltersResolution > 0) {
123
+ queryParams.spatialFiltersResolution = spatialFiltersResolution;
124
+ }
125
+ queryParams.spatialFiltersMode = spatialFiltersMode;
111
126
  }
112
127
 
113
128
  const urlWithSearchParams =
114
- url + '?' + new URLSearchParams(queryParams).toString();
129
+ url + '?' + objectToURLSearchParams(queryParams).toString();
115
130
  const isGet = urlWithSearchParams.length <= REQUEST_GET_MAX_URL_LENGTH;
116
131
  if (isGet) {
117
132
  url = urlWithSearchParams;
118
- } else {
119
- // undo the JSON.stringify, @TODO find a better pattern
120
- queryParams.params = params as $TODO;
121
- queryParams.filters = filters as $TODO;
122
- queryParams.queryParameters = source.queryParameters as $TODO;
123
- if (spatialFilters) {
124
- queryParams.spatialFilters = spatialFilters as $TODO;
125
- }
126
133
  }
127
134
  return makeCall({
128
135
  url,
@@ -134,3 +141,19 @@ export function executeModel(props: {
134
141
  },
135
142
  });
136
143
  }
144
+
145
+ function objectToURLSearchParams(object: Record<string, unknown>) {
146
+ const params = new URLSearchParams();
147
+ for (const key in object) {
148
+ if (isPureObject(object[key])) {
149
+ params.append(key, JSON.stringify(object[key]));
150
+ } else if (Array.isArray(object[key])) {
151
+ params.append(key, JSON.stringify(object[key]));
152
+ } else if (object[key] === null) {
153
+ params.append(key, 'null');
154
+ } else if (object[key] !== undefined) {
155
+ params.append(key, String(object[key]));
156
+ }
157
+ }
158
+ return params;
159
+ }
@@ -19,6 +19,7 @@ export type H3QuerySourceOptions = SourceOptions &
19
19
  QuerySourceOptions &
20
20
  AggregationOptions &
21
21
  FilterOptions;
22
+
22
23
  type UrlParameters = {
23
24
  aggregationExp: string;
24
25
  aggregationResLevel?: string;
@@ -59,7 +60,12 @@ export const h3QuerySource = async function (
59
60
  return baseSource<UrlParameters>('query', options, urlParameters).then(
60
61
  (result) => ({
61
62
  ...(result as TilejsonResult),
62
- widgetSource: new WidgetQuerySource(options),
63
+ widgetSource: new WidgetQuerySource({
64
+ ...options,
65
+ // NOTE: passing redundant spatialDataColumn here to apply the default value 'h3'
66
+ spatialDataColumn,
67
+ spatialDataType: 'h3',
68
+ }),
63
69
  })
64
70
  );
65
71
  };
@@ -55,7 +55,12 @@ export const h3TableSource = async function (
55
55
  return baseSource<UrlParameters>('table', options, urlParameters).then(
56
56
  (result) => ({
57
57
  ...(result as TilejsonResult),
58
- widgetSource: new WidgetTableSource(options),
58
+ widgetSource: new WidgetTableSource({
59
+ ...options,
60
+ // NOTE: passing redundant spatialDataColumn here to apply the default value 'h3'
61
+ spatialDataColumn,
62
+ spatialDataType: 'h3',
63
+ }),
59
64
  })
60
65
  );
61
66
  };
@@ -60,7 +60,12 @@ export const quadbinQuerySource = async function (
60
60
  return baseSource<UrlParameters>('query', options, urlParameters).then(
61
61
  (result) => ({
62
62
  ...(result as TilejsonResult),
63
- widgetSource: new WidgetQuerySource(options),
63
+ widgetSource: new WidgetQuerySource({
64
+ ...options,
65
+ // NOTE: passing redundant spatialDataColumn here to apply the default value 'quadbin'
66
+ spatialDataColumn,
67
+ spatialDataType: 'quadbin',
68
+ }),
64
69
  })
65
70
  );
66
71
  };
@@ -56,7 +56,12 @@ export const quadbinTableSource = async function (
56
56
  return baseSource<UrlParameters>('table', options, urlParameters).then(
57
57
  (result) => ({
58
58
  ...(result as TilejsonResult),
59
- widgetSource: new WidgetTableSource(options),
59
+ widgetSource: new WidgetTableSource({
60
+ ...options,
61
+ // NOTE: passing redundant spatialDataColumn here to apply the default value 'quadbin'
62
+ spatialDataColumn,
63
+ spatialDataType: 'quadbin',
64
+ }),
60
65
  })
61
66
  );
62
67
  };
@@ -48,6 +48,33 @@ export type SourceOptionalOptions = {
48
48
  */
49
49
  maxLengthURL?: number;
50
50
 
51
+ /**
52
+ * The column name and the type of geospatial support.
53
+ *
54
+ * If not present, defaults to `'geom'` for generic queries, `'quadbin'` for Quadbin sources and `'h3'` for H3 sources.
55
+ */
56
+ spatialDataColumn?: string;
57
+
58
+ /**
59
+ * The type of geospatial support. Defaults to `'geo'`.
60
+ */
61
+ spatialDataType?: SpatialDataType;
62
+
63
+ /**
64
+ * Relative resolution of a tile. Higher values increase density and data size. At `tileResolution = 1`, tile geometry is
65
+ * quantized to a 1024x1024 grid. Increasing or decreasing the resolution will increase or decrease the dimensions of
66
+ * the quantization grid proportionately.
67
+ *
68
+ * Supported `tileResolution` values, with corresponding grid sizes:
69
+ *
70
+ * - 0.25: 256x256
71
+ * - 0.5: 512x512
72
+ * - 1: 1024x1024
73
+ * - 2: 2048x2048
74
+ * - 4: 4096x4096
75
+ */
76
+ tileResolution?: TileResolution;
77
+
51
78
  /**
52
79
  * By default, local in-memory caching is enabled.
53
80
  */
@@ -89,6 +116,11 @@ export type AggregationOptions = {
89
116
  * @default 6 for quadbin and 4 for h3 sources
90
117
  */
91
118
  aggregationResLevel?: number;
119
+
120
+ /**
121
+ * Original resolution of the spatial index data as stored in the DW
122
+ */
123
+ dataResolution?: number;
92
124
  };
93
125
 
94
126
  export type FilterOptions = {
@@ -99,31 +131,9 @@ export type FilterOptions = {
99
131
  };
100
132
 
101
133
  export type QuerySourceOptions = {
102
- /**
103
- * The column name and the type of geospatial support.
104
- *
105
- * If not present, defaults to `'geom'` for generic queries, `'quadbin'` for Quadbin sources and `'h3'` for H3 sources.
106
- */
107
- spatialDataColumn?: string;
108
-
109
- /** SQL query. */
134
+ /** Full SQL query with query paremeter placeholders (if any). */
110
135
  sqlQuery: string;
111
136
 
112
- /**
113
- * Relative resolution of a tile. Higher values increase density and data size. At `tileResolution = 1`, tile geometry is
114
- * quantized to a 1024x1024 grid. Increasing or decreasing the resolution will increase or decrease the dimensions of
115
- * the quantization grid proportionately.
116
- *
117
- * Supported `tileResolution` values, with corresponding grid sizes:
118
- *
119
- * - 0.25: 256x256
120
- * - 0.5: 512x512
121
- * - 1: 1024x1024
122
- * - 2: 2048x2048
123
- * - 4: 4096x4096
124
- */
125
- tileResolution?: TileResolution;
126
-
127
137
  /**
128
138
  * Values for named or positional paramteres in the query.
129
139
  *
@@ -156,28 +166,6 @@ export type TableSourceOptions = {
156
166
  * Fully qualified name of table.
157
167
  */
158
168
  tableName: string;
159
-
160
- /**
161
- * The column name and the type of geospatial support.
162
- *
163
- * If not present, defaults to `'geom'` for generic tables, `'quadbin'` for Quadbin sources and `'h3'` for H3 sources.
164
- */
165
- spatialDataColumn?: string;
166
-
167
- /**
168
- * Relative resolution of a tile. Higher values increase density and data size. At `tileResolution = 1`, tile geometry is
169
- * quantized to a 1024x1024 grid. Increasing or decreasing the resolution will increase or decrease the dimensions of
170
- * the quantization grid proportionately.
171
- *
172
- * Supported `tileResolution` values, with corresponding grid sizes:
173
- *
174
- * - 0.25: 256x256
175
- * - 0.5: 512x512
176
- * - 1: 1024x1024
177
- * - 2: 2048x2048
178
- * - 4: 4096x4096
179
- */
180
- tileResolution?: TileResolution;
181
169
  };
182
170
 
183
171
  export type TilesetSourceOptions = {
@@ -198,6 +186,14 @@ export type ColumnsOption = {
198
186
 
199
187
  export type SpatialDataType = 'geo' | 'h3' | 'quadbin';
200
188
 
189
+ /**
190
+ * Strategy used for covering spatial filter geometry with spatial indexes.
191
+ * See https://docs.carto.com/data-and-analysis/analytics-toolbox-for-bigquery/sql-reference/quadbin#quadbin_polyfill_mode
192
+ * or https://docs.carto.com/data-and-analysis/analytics-toolbox-for-bigquery/sql-reference/h3#h3_polyfill_mode for more information.
193
+ * @internalRemarks Source: cloud-native maps-api
194
+ * */
195
+ export type SpatialFilterPolyfillMode = 'center' | 'intersects' | 'contains';
196
+
201
197
  export type TilejsonMapInstantiation = MapInstantiation & {
202
198
  tilejson: {url: string[]};
203
199
  };
@@ -64,7 +64,10 @@ export const vectorQuerySource = async function (
64
64
  return baseSource<UrlParameters>('query', options, urlParameters).then(
65
65
  (result) => ({
66
66
  ...(result as TilejsonResult),
67
- widgetSource: new WidgetQuerySource(options),
67
+ widgetSource: new WidgetQuerySource({
68
+ ...options,
69
+ spatialDataType: 'geo',
70
+ }),
68
71
  })
69
72
  );
70
73
  };
@@ -22,6 +22,7 @@ export type VectorTableSourceOptions = SourceOptions &
22
22
  TableSourceOptions &
23
23
  FilterOptions &
24
24
  ColumnsOption;
25
+
25
26
  type UrlParameters = {
26
27
  columns?: string;
27
28
  filters?: Record<string, unknown>;
@@ -58,7 +59,10 @@ export const vectorTableSource = async function (
58
59
  return baseSource<UrlParameters>('table', options, urlParameters).then(
59
60
  (result) => ({
60
61
  ...(result as TilejsonResult),
61
- widgetSource: new WidgetTableSource(options),
62
+ widgetSource: new WidgetTableSource({
63
+ ...options,
64
+ spatialDataType: 'geo',
65
+ }),
62
66
  })
63
67
  );
64
68
  };
@@ -0,0 +1,119 @@
1
+ import {
2
+ DEFAULT_AGGREGATION_RES_LEVEL_H3,
3
+ DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN,
4
+ } from './constants-internal';
5
+ import type {ModelSource} from './models/model';
6
+ import type {AggregationOptions} from './sources/types';
7
+ import {assert} from './utils';
8
+ import type {ViewState} from './widget-sources';
9
+
10
+ const DEFAULT_TILE_SIZE = 512;
11
+ const QUADBIN_ZOOM_MAX_OFFSET = 4;
12
+
13
+ export function getSpatialFiltersResolution({
14
+ source,
15
+ viewState,
16
+ }: {
17
+ source: Partial<ModelSource & AggregationOptions>;
18
+ viewState?: ViewState;
19
+ }) {
20
+ assert(
21
+ viewState,
22
+ 'viewState prop is required to compute automatic spatialFiltersResolution when using spatialFilter with spatial indexes. Either pass a `spatialFiltersResolution` prop or a `viewState` prop to avoid this error'
23
+ );
24
+
25
+ const dataResolution = source.dataResolution ?? Number.MAX_VALUE;
26
+
27
+ const aggregationResLevel =
28
+ source.aggregationResLevel ??
29
+ (source.spatialDataType === 'h3'
30
+ ? DEFAULT_AGGREGATION_RES_LEVEL_H3
31
+ : DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN);
32
+
33
+ const aggregationResLevelOffset = Math.max(
34
+ 0,
35
+ Math.floor(aggregationResLevel)
36
+ );
37
+
38
+ const currentZoomInt = Math.ceil(viewState.zoom);
39
+ if (source.spatialDataType === 'h3') {
40
+ const tileSize = DEFAULT_TILE_SIZE;
41
+ const maxResolutionForZoom =
42
+ maxH3SpatialFiltersResolutions.find(
43
+ ([zoom]) => zoom === currentZoomInt
44
+ )?.[1] ?? Math.max(0, currentZoomInt - 3);
45
+
46
+ const maxSpatialFiltersResolution = maxResolutionForZoom
47
+ ? Math.min(dataResolution, maxResolutionForZoom)
48
+ : dataResolution;
49
+
50
+ const hexagonResolution =
51
+ getHexagonResolution(viewState, tileSize) + aggregationResLevelOffset;
52
+
53
+ return Math.min(hexagonResolution, maxSpatialFiltersResolution);
54
+ }
55
+
56
+ if (source.spatialDataType === 'quadbin') {
57
+ const maxResolutionForZoom = currentZoomInt + QUADBIN_ZOOM_MAX_OFFSET;
58
+ const maxSpatialFiltersResolution = Math.min(
59
+ dataResolution,
60
+ maxResolutionForZoom
61
+ );
62
+
63
+ const quadsResolution =
64
+ Math.floor(viewState.zoom) + aggregationResLevelOffset;
65
+ return Math.min(quadsResolution, maxSpatialFiltersResolution);
66
+ }
67
+
68
+ return undefined;
69
+ }
70
+
71
+ const maxH3SpatialFiltersResolutions = [
72
+ [20, 14],
73
+ [19, 13],
74
+ [18, 12],
75
+ [17, 11],
76
+ [16, 10],
77
+ [15, 9],
78
+ [14, 8],
79
+ [13, 7],
80
+ [12, 7],
81
+ [11, 7],
82
+ [10, 6],
83
+ [9, 6],
84
+ [8, 5],
85
+ [7, 4],
86
+ [6, 4],
87
+ [5, 3],
88
+ [4, 2],
89
+ [3, 1],
90
+ [2, 1],
91
+ [1, 0],
92
+ ];
93
+
94
+ // stolen from https://github.com/visgl/deck.gl/blob/master/modules/carto/src/layers/h3-tileset-2d.ts
95
+
96
+ // Relative scale factor (0 = no biasing, 2 = a few hexagons cover view)
97
+ const BIAS = 2;
98
+
99
+ // Resolution conversion function. Takes a WebMercatorViewport and returns
100
+ // a H3 resolution such that the screen space size of the hexagons is
101
+ // similar
102
+ export function getHexagonResolution(
103
+ viewport: {zoom: number; latitude: number},
104
+ tileSize: number
105
+ ): number {
106
+ // Difference in given tile size compared to deck's internal 512px tile size,
107
+ // expressed as an offset to the viewport zoom.
108
+ const zoomOffset = Math.log2(tileSize / DEFAULT_TILE_SIZE);
109
+ const hexagonScaleFactor = (2 / 3) * (viewport.zoom - zoomOffset);
110
+ const latitudeScaleFactor = Math.log(
111
+ 1 / Math.cos((Math.PI * viewport.latitude) / 180)
112
+ );
113
+
114
+ // Clip and bias
115
+ return Math.max(
116
+ 0,
117
+ Math.floor(hexagonScaleFactor + latitudeScaleFactor - BIAS)
118
+ );
119
+ }
package/src/utils.ts CHANGED
@@ -57,7 +57,7 @@ export function normalizeObjectKeys<T, R extends Row<T>>(el: R): R {
57
57
  }
58
58
 
59
59
  /** @internalRemarks Source: @carto/react-core */
60
- export function assert(condition: unknown, message: string) {
60
+ export function assert(condition: unknown, message: string): asserts condition {
61
61
  if (!condition) {
62
62
  throw new Error(message);
63
63
  }