@carto/api-client 0.4.3 → 0.4.5-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.
@@ -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
  *
@@ -166,28 +176,6 @@ export type TableSourceOptions = {
166
176
  */
167
177
  tableName: string;
168
178
 
169
- /**
170
- * The column name and the type of geospatial support.
171
- *
172
- * If not present, defaults to `'geom'` for generic tables, `'quadbin'` for Quadbin sources and `'h3'` for H3 sources.
173
- */
174
- spatialDataColumn?: string;
175
-
176
- /**
177
- * Relative resolution of a tile. Higher values increase density and data size. At `tileResolution = 1`, tile geometry is
178
- * quantized to a 1024x1024 grid. Increasing or decreasing the resolution will increase or decrease the dimensions of
179
- * the quantization grid proportionately.
180
- *
181
- * Supported `tileResolution` values, with corresponding grid sizes:
182
- *
183
- * - 0.25: 256x256
184
- * - 0.5: 512x512
185
- * - 1: 1024x1024
186
- * - 2: 2048x2048
187
- * - 4: 4096x4096
188
- */
189
- tileResolution?: TileResolution;
190
-
191
179
  /**
192
180
  * Comma-separated aggregation expressions. If assigned on a vector source, source is grouped by geometry and then aggregated.
193
181
  *
@@ -216,6 +204,14 @@ export type ColumnsOption = {
216
204
 
217
205
  export type SpatialDataType = 'geo' | 'h3' | 'quadbin';
218
206
 
207
+ /**
208
+ * Strategy used for covering spatial filter geometry with spatial indexes.
209
+ * See https://docs.carto.com/data-and-analysis/analytics-toolbox-for-bigquery/sql-reference/quadbin#quadbin_polyfill_mode
210
+ * or https://docs.carto.com/data-and-analysis/analytics-toolbox-for-bigquery/sql-reference/h3#h3_polyfill_mode for more information.
211
+ * @internalRemarks Source: cloud-native maps-api
212
+ * */
213
+ export type SpatialFilterPolyfillMode = 'center' | 'intersects' | 'contains';
214
+
219
215
  export type TilejsonMapInstantiation = MapInstantiation & {
220
216
  tilejson: {url: string[]};
221
217
  };
@@ -50,9 +50,11 @@ export const vectorQuerySource = async function (
50
50
  aggregationExp,
51
51
  } = options;
52
52
 
53
+ const spatialDataType = 'geo';
54
+
53
55
  const urlParameters: UrlParameters = {
54
56
  spatialDataColumn,
55
- spatialDataType: 'geo',
57
+ spatialDataType,
56
58
  tileResolution: tileResolution.toString(),
57
59
  q: sqlQuery,
58
60
  };
@@ -69,10 +71,17 @@ export const vectorQuerySource = async function (
69
71
  if (aggregationExp) {
70
72
  urlParameters.aggregationExp = aggregationExp;
71
73
  }
74
+
72
75
  return baseSource<UrlParameters>('query', options, urlParameters).then(
73
76
  (result) => ({
74
77
  ...(result as TilejsonResult),
75
- widgetSource: new WidgetQuerySource(options),
78
+ widgetSource: new WidgetQuerySource({
79
+ ...options,
80
+ // NOTE: Parameters with default values above must be explicitly passed here.
81
+ spatialDataColumn,
82
+ spatialDataType,
83
+ tileResolution,
84
+ }),
76
85
  })
77
86
  );
78
87
  };
@@ -48,10 +48,12 @@ export const vectorTableSource = async function (
48
48
  aggregationExp,
49
49
  } = options;
50
50
 
51
+ const spatialDataType = 'geo';
52
+
51
53
  const urlParameters: UrlParameters = {
52
54
  name: tableName,
53
55
  spatialDataColumn,
54
- spatialDataType: 'geo',
56
+ spatialDataType,
55
57
  tileResolution: tileResolution.toString(),
56
58
  };
57
59
 
@@ -64,10 +66,17 @@ export const vectorTableSource = async function (
64
66
  if (aggregationExp) {
65
67
  urlParameters.aggregationExp = aggregationExp;
66
68
  }
69
+
67
70
  return baseSource<UrlParameters>('table', options, urlParameters).then(
68
71
  (result) => ({
69
72
  ...(result as TilejsonResult),
70
- widgetSource: new WidgetTableSource(options),
73
+ widgetSource: new WidgetTableSource({
74
+ ...options,
75
+ // NOTE: Parameters with default values above must be explicitly passed here.
76
+ spatialDataColumn,
77
+ spatialDataType,
78
+ tileResolution,
79
+ }),
71
80
  })
72
81
  );
73
82
  };
@@ -0,0 +1,111 @@
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: Partial<ModelSource & AggregationOptions>,
15
+ viewState: ViewState
16
+ ): number | undefined {
17
+ const dataResolution = source.dataResolution ?? Number.MAX_VALUE;
18
+
19
+ const aggregationResLevel =
20
+ source.aggregationResLevel ??
21
+ (source.spatialDataType === 'h3'
22
+ ? DEFAULT_AGGREGATION_RES_LEVEL_H3
23
+ : DEFAULT_AGGREGATION_RES_LEVEL_QUADBIN);
24
+
25
+ const aggregationResLevelOffset = Math.max(
26
+ 0,
27
+ Math.floor(aggregationResLevel)
28
+ );
29
+
30
+ const currentZoomInt = Math.ceil(viewState.zoom);
31
+ if (source.spatialDataType === 'h3') {
32
+ const tileSize = DEFAULT_TILE_SIZE;
33
+ const maxResolutionForZoom =
34
+ maxH3SpatialFiltersResolutions.find(
35
+ ([zoom]) => zoom === currentZoomInt
36
+ )?.[1] ?? Math.max(0, currentZoomInt - 3);
37
+
38
+ const maxSpatialFiltersResolution = maxResolutionForZoom
39
+ ? Math.min(dataResolution, maxResolutionForZoom)
40
+ : dataResolution;
41
+
42
+ const hexagonResolution =
43
+ getHexagonResolution(viewState, tileSize) + aggregationResLevelOffset;
44
+
45
+ return Math.min(hexagonResolution, maxSpatialFiltersResolution);
46
+ }
47
+
48
+ if (source.spatialDataType === 'quadbin') {
49
+ const maxResolutionForZoom = currentZoomInt + QUADBIN_ZOOM_MAX_OFFSET;
50
+ const maxSpatialFiltersResolution = Math.min(
51
+ dataResolution,
52
+ maxResolutionForZoom
53
+ );
54
+
55
+ const quadsResolution =
56
+ Math.floor(viewState.zoom) + aggregationResLevelOffset;
57
+ return Math.min(quadsResolution, maxSpatialFiltersResolution);
58
+ }
59
+
60
+ return undefined;
61
+ }
62
+
63
+ const maxH3SpatialFiltersResolutions = [
64
+ [20, 14],
65
+ [19, 13],
66
+ [18, 12],
67
+ [17, 11],
68
+ [16, 10],
69
+ [15, 9],
70
+ [14, 8],
71
+ [13, 7],
72
+ [12, 7],
73
+ [11, 7],
74
+ [10, 6],
75
+ [9, 6],
76
+ [8, 5],
77
+ [7, 4],
78
+ [6, 4],
79
+ [5, 3],
80
+ [4, 2],
81
+ [3, 1],
82
+ [2, 1],
83
+ [1, 0],
84
+ ];
85
+
86
+ // stolen from https://github.com/visgl/deck.gl/blob/master/modules/carto/src/layers/h3-tileset-2d.ts
87
+
88
+ // Relative scale factor (0 = no biasing, 2 = a few hexagons cover view)
89
+ const BIAS = 2;
90
+
91
+ // Resolution conversion function. Takes a WebMercatorViewport and returns
92
+ // a H3 resolution such that the screen space size of the hexagons is
93
+ // similar
94
+ export function getHexagonResolution(
95
+ viewport: {zoom: number; latitude: number},
96
+ tileSize: number
97
+ ): number {
98
+ // Difference in given tile size compared to deck's internal 512px tile size,
99
+ // expressed as an offset to the viewport zoom.
100
+ const zoomOffset = Math.log2(tileSize / DEFAULT_TILE_SIZE);
101
+ const hexagonScaleFactor = (2 / 3) * (viewport.zoom - zoomOffset);
102
+ const latitudeScaleFactor = Math.log(
103
+ 1 / Math.cos((Math.PI * viewport.latitude) / 180)
104
+ );
105
+
106
+ // Clip and bias
107
+ return Math.max(
108
+ 0,
109
+ Math.floor(hexagonScaleFactor + latitudeScaleFactor - BIAS)
110
+ );
111
+ }
package/src/utils.ts CHANGED
@@ -49,15 +49,18 @@ export function normalizeObjectKeys<T, R extends Row<T>>(el: R): R {
49
49
  return el;
50
50
  }
51
51
 
52
- return Object.entries(el as Record<string, T>).reduce((acc, [key, value]) => {
53
- acc[key.toLowerCase()] =
54
- typeof value === 'object' && value ? normalizeObjectKeys(value) : value;
55
- return acc;
56
- }, {} as Record<string, T>) as R;
52
+ return Object.entries(el as Record<string, T>).reduce(
53
+ (acc, [key, value]) => {
54
+ acc[key.toLowerCase()] =
55
+ typeof value === 'object' && value ? normalizeObjectKeys(value) : value;
56
+ return acc;
57
+ },
58
+ {} as Record<string, T>
59
+ ) as R;
57
60
  }
58
61
 
59
62
  /** @internalRemarks Source: @carto/react-core */
60
- export function assert(condition: unknown, message: string) {
63
+ export function assert(condition: unknown, message: string): asserts condition {
61
64
  if (!condition) {
62
65
  throw new Error(message);
63
66
  }
@@ -1,4 +1,4 @@
1
- import {TileResolution} from '../sources/types';
1
+ import {SpatialFilterPolyfillMode, TileResolution} from '../sources/types';
2
2
  import {
3
3
  GroupDateType,
4
4
  SortColumnType,
@@ -10,9 +10,18 @@ import {
10
10
  * WIDGET API REQUESTS
11
11
  */
12
12
 
13
+ export interface ViewState {
14
+ zoom: number;
15
+ latitude: number;
16
+ longitude: number;
17
+ }
18
+
13
19
  /** Common options for {@link WidgetBaseSource} requests. */
14
20
  interface BaseRequestOptions {
15
21
  spatialFilter?: SpatialFilter;
22
+ spatialFiltersMode?: SpatialFilterPolyfillMode;
23
+ /** Required for table- and query-based spatial index sources (H3, Quadbin). */
24
+ spatialIndexReferenceViewState?: ViewState;
16
25
  abortController?: AbortController;
17
26
  filterOwner?: string;
18
27
  }