@deck.gl/carto 9.0.16 → 9.0.18

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.
Files changed (50) hide show
  1. package/dist/api/carto-api-error.d.ts +3 -1
  2. package/dist/api/carto-api-error.d.ts.map +1 -1
  3. package/dist/api/carto-api-error.js +2 -1
  4. package/dist/api/common.d.ts +0 -8
  5. package/dist/api/common.d.ts.map +1 -1
  6. package/dist/api/common.js +0 -9
  7. package/dist/api/request-with-parameters.d.ts +1 -1
  8. package/dist/api/request-with-parameters.d.ts.map +1 -1
  9. package/dist/api/request-with-parameters.js +48 -15
  10. package/dist/api/types.d.ts +5 -5
  11. package/dist/api/types.d.ts.map +1 -1
  12. package/dist/cartoRasterTile-worker.js +1 -1
  13. package/dist/cartoSpatialTile-worker.js +1 -1
  14. package/dist/cartoVectorTile-worker.js +1 -1
  15. package/dist/dist.dev.js +494 -560
  16. package/dist/index.cjs +445 -358
  17. package/dist/index.cjs.map +4 -4
  18. package/dist/index.d.ts +3 -3
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +3 -3
  21. package/dist/layers/heatmap-tile-layer.d.ts +36 -0
  22. package/dist/layers/heatmap-tile-layer.d.ts.map +1 -0
  23. package/dist/layers/heatmap-tile-layer.js +165 -0
  24. package/dist/layers/heatmap.d.ts +5 -0
  25. package/dist/layers/heatmap.d.ts.map +1 -1
  26. package/dist/layers/heatmap.js +17 -15
  27. package/dist/layers/schema/carto-raster-tile-loader.js +1 -1
  28. package/dist/layers/schema/carto-spatial-tile-loader.js +1 -1
  29. package/dist/layers/schema/carto-vector-tile-loader.js +1 -1
  30. package/dist/layers/vector-tile-layer.d.ts +1 -1
  31. package/dist/layers/vector-tile-layer.d.ts.map +1 -1
  32. package/dist/layers/vector-tile-layer.js +5 -10
  33. package/dist/sources/raster-source.d.ts +2 -2
  34. package/dist/sources/raster-source.d.ts.map +1 -1
  35. package/dist/sources/raster-source.js +4 -1
  36. package/dist.min.js +37 -31
  37. package/package.json +2 -2
  38. package/src/api/carto-api-error.ts +10 -1
  39. package/src/api/common.ts +0 -12
  40. package/src/api/request-with-parameters.ts +55 -19
  41. package/src/api/types.ts +5 -5
  42. package/src/index.ts +3 -3
  43. package/src/layers/heatmap-tile-layer.ts +236 -0
  44. package/src/layers/heatmap.ts +31 -18
  45. package/src/layers/vector-tile-layer.ts +4 -14
  46. package/src/sources/raster-source.ts +10 -5
  47. package/dist/layers/quadbin-heatmap-tile-layer.d.ts +0 -24
  48. package/dist/layers/quadbin-heatmap-tile-layer.d.ts.map +0 -1
  49. package/dist/layers/quadbin-heatmap-tile-layer.js +0 -84
  50. package/src/layers/quadbin-heatmap-tile-layer.ts +0 -125
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "CARTO official integration with Deck.gl. Build geospatial applications using CARTO and Deck.gl.",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
- "version": "9.0.16",
6
+ "version": "9.0.18",
7
7
  "publishConfig": {
8
8
  "access": "public"
9
9
  },
@@ -73,5 +73,5 @@
73
73
  "@deck.gl/layers": "^9.0.0",
74
74
  "@loaders.gl/core": "^4.2.0"
75
75
  },
76
- "gitHead": "87e1629767fae5167a43dc9fa04786a16879f7aa"
76
+ "gitHead": "32f7e51eb96319739a18a3ca22092e60948fcbdb"
77
77
  }
@@ -16,7 +16,15 @@ export class CartoAPIError extends Error {
16
16
  /** Response from server */
17
17
  response?: Response;
18
18
 
19
- constructor(error: Error, errorContext: APIErrorContext, response?: Response) {
19
+ /** JSON Response from server */
20
+ responseJson?: any;
21
+
22
+ constructor(
23
+ error: Error,
24
+ errorContext: APIErrorContext,
25
+ response?: Response,
26
+ responseJson?: any
27
+ ) {
20
28
  let responseString = 'Failed to connect';
21
29
  if (response) {
22
30
  responseString = 'Server returned: ';
@@ -46,6 +54,7 @@ export class CartoAPIError extends Error {
46
54
 
47
55
  this.name = 'CartoAPIError';
48
56
  this.response = response;
57
+ this.responseJson = responseJson;
49
58
  this.error = error;
50
59
  this.errorContext = errorContext;
51
60
  }
package/src/api/common.ts CHANGED
@@ -1,16 +1,4 @@
1
- import {VERSION} from '@deck.gl/core';
2
-
3
1
  export const DEFAULT_API_BASE_URL = 'https://gcp-us-east1.api.carto.com';
4
2
  export const DEFAULT_CLIENT = 'deck-gl-carto';
5
3
  export const V3_MINOR_VERSION = '3.4';
6
4
  export const MAX_GET_LENGTH = 8192;
7
-
8
- export const DEFAULT_PARAMETERS = {
9
- v: V3_MINOR_VERSION,
10
- deckglVersion: VERSION
11
- };
12
-
13
- export const DEFAULT_HEADERS = {
14
- Accept: 'application/json',
15
- 'Content-Type': 'application/json'
16
- };
@@ -1,37 +1,45 @@
1
+ import {VERSION} from '@deck.gl/core';
1
2
  import {isPureObject} from '../utils';
2
3
  import {CartoAPIError} from './carto-api-error';
3
- import {DEFAULT_HEADERS, DEFAULT_PARAMETERS, MAX_GET_LENGTH} from './common';
4
+ import {MAX_GET_LENGTH, V3_MINOR_VERSION} from './common';
4
5
  import type {APIErrorContext} from './types';
5
6
 
6
7
  /**
7
- * Simple encode parameter
8
+ * Parameters added to all requests issued with `requestWithParameters()`.
9
+ * These parameters override parameters already in the base URL, but not
10
+ * user-provided parameters.
8
11
  */
9
- function encodeParameter(name: string, value: unknown): string {
10
- if (isPureObject(value) || Array.isArray(value)) {
11
- return `${name}=${encodeURIComponent(JSON.stringify(value))}`;
12
- }
13
- return `${name}=${encodeURIComponent(value as string | boolean | number)}`;
14
- }
12
+ const DEFAULT_PARAMETERS = {
13
+ v: V3_MINOR_VERSION,
14
+ deckglVersion: VERSION
15
+ };
16
+
17
+ const DEFAULT_HEADERS = {
18
+ Accept: 'application/json',
19
+ 'Content-Type': 'application/json'
20
+ };
15
21
 
16
22
  const REQUEST_CACHE = new Map<string, Promise<unknown>>();
23
+
17
24
  export async function requestWithParameters<T = any>({
18
25
  baseUrl,
19
- parameters,
20
- headers: customHeaders,
26
+ parameters = {},
27
+ headers: customHeaders = {},
21
28
  errorContext
22
29
  }: {
23
30
  baseUrl: string;
24
31
  parameters?: Record<string, unknown>;
25
- headers: Record<string, string>;
32
+ headers?: Record<string, string>;
26
33
  errorContext: APIErrorContext;
27
34
  }): Promise<T> {
28
35
  parameters = {...DEFAULT_PARAMETERS, ...parameters};
29
- const key = createCacheKey(baseUrl, parameters || {}, customHeaders || {});
36
+ baseUrl = excludeURLParameters(baseUrl, Object.keys(parameters));
37
+ const key = createCacheKey(baseUrl, parameters, customHeaders);
30
38
  if (REQUEST_CACHE.has(key)) {
31
39
  return REQUEST_CACHE.get(key) as Promise<T>;
32
40
  }
33
41
 
34
- const url = parameters ? createURLWithParameters(baseUrl, parameters) : baseUrl;
42
+ const url = createURLWithParameters(baseUrl, parameters);
35
43
  const headers = {...DEFAULT_HEADERS, ...customHeaders};
36
44
 
37
45
  /* global fetch */
@@ -41,12 +49,14 @@ export async function requestWithParameters<T = any>({
41
49
  : fetch(url, {headers});
42
50
 
43
51
  let response: Response | undefined;
52
+ let responseJson;
44
53
  const jsonPromise: Promise<T> = fetchPromise
45
54
  .then((_response: Response) => {
46
55
  response = _response;
47
56
  return response.json();
48
57
  })
49
58
  .then((json: any) => {
59
+ responseJson = json;
50
60
  if (!response || !response.ok) {
51
61
  throw new Error(json.error);
52
62
  }
@@ -54,7 +64,7 @@ export async function requestWithParameters<T = any>({
54
64
  })
55
65
  .catch((error: Error) => {
56
66
  REQUEST_CACHE.delete(key);
57
- throw new CartoAPIError(error, errorContext, response);
67
+ throw new CartoAPIError(error, errorContext, response, responseJson);
58
68
  });
59
69
 
60
70
  REQUEST_CACHE.set(key, jsonPromise);
@@ -71,9 +81,35 @@ function createCacheKey(
71
81
  return JSON.stringify({baseUrl, parameters: parameterEntries, headers: headerEntries});
72
82
  }
73
83
 
74
- function createURLWithParameters(baseUrl: string, parameters: Record<string, unknown>): string {
75
- const encodedParameters = Object.entries(parameters).map(([key, value]) =>
76
- encodeParameter(key, value)
77
- );
78
- return `${baseUrl}?${encodedParameters.join('&')}`;
84
+ /**
85
+ * Appends query string parameters to a URL. Existing URL parameters are kept,
86
+ * unless there is a conflict, in which case the new parameters override
87
+ * those already in the URL.
88
+ */
89
+ function createURLWithParameters(
90
+ baseUrlString: string,
91
+ parameters: Record<string, unknown>
92
+ ): string {
93
+ const baseUrl = new URL(baseUrlString);
94
+ for (const [key, value] of Object.entries(parameters)) {
95
+ if (isPureObject(value) || Array.isArray(value)) {
96
+ baseUrl.searchParams.set(key, JSON.stringify(value));
97
+ } else {
98
+ baseUrl.searchParams.set(key, (value as string | boolean | number).toString());
99
+ }
100
+ }
101
+ return baseUrl.toString();
102
+ }
103
+
104
+ /**
105
+ * Deletes query string parameters from a URL.
106
+ */
107
+ function excludeURLParameters(baseUrlString: string, parameters: string[]) {
108
+ const baseUrl = new URL(baseUrlString);
109
+ for (const param of parameters) {
110
+ if (baseUrl.searchParams.has(param)) {
111
+ baseUrl.searchParams.delete(param);
112
+ }
113
+ }
114
+ return baseUrl.toString();
79
115
  }
package/src/api/types.ts CHANGED
@@ -66,11 +66,11 @@ export interface Filters {
66
66
  }
67
67
 
68
68
  interface Filter {
69
- [FilterTypes.In]: number[];
70
- [FilterTypes.Between]: number[][];
71
- [FilterTypes.ClosedOpen]: number[][];
72
- [FilterTypes.Time]: number[][];
73
- [FilterTypes.StringSearch]: string[];
69
+ [FilterTypes.In]?: number[];
70
+ [FilterTypes.Between]?: number[][];
71
+ [FilterTypes.ClosedOpen]?: number[][];
72
+ [FilterTypes.Time]?: number[][];
73
+ [FilterTypes.StringSearch]?: string[];
74
74
  }
75
75
 
76
76
  export enum FilterTypes {
package/src/index.ts CHANGED
@@ -1,23 +1,23 @@
1
1
  import {default as H3TileLayer} from './layers/h3-tile-layer';
2
+ import {default as HeatmapTileLayer} from './layers/heatmap-tile-layer';
2
3
  import {default as _PointLabelLayer} from './layers/point-label-layer';
3
4
  import {default as QuadbinTileLayer} from './layers/quadbin-tile-layer';
4
- import {default as QuadbinHeatmapTileLayer} from './layers/quadbin-heatmap-tile-layer';
5
5
  import {default as RasterTileLayer} from './layers/raster-tile-layer';
6
6
  import {default as VectorTileLayer} from './layers/vector-tile-layer';
7
7
  const CARTO_LAYERS = {
8
8
  H3TileLayer,
9
+ HeatmapTileLayer,
9
10
  _PointLabelLayer,
10
11
  QuadbinTileLayer,
11
- QuadbinHeatmapTileLayer,
12
12
  RasterTileLayer,
13
13
  VectorTileLayer
14
14
  };
15
15
  export {
16
16
  CARTO_LAYERS,
17
17
  H3TileLayer,
18
+ HeatmapTileLayer,
18
19
  _PointLabelLayer,
19
20
  QuadbinTileLayer,
20
- QuadbinHeatmapTileLayer,
21
21
  RasterTileLayer,
22
22
  VectorTileLayer
23
23
  };
@@ -0,0 +1,236 @@
1
+ import {getResolution} from 'quadbin';
2
+
3
+ import {Accessor, CompositeLayer, CompositeLayerProps, DefaultProps, Layer} from '@deck.gl/core';
4
+ import {SolidPolygonLayer} from '@deck.gl/layers';
5
+
6
+ import {HeatmapProps, heatmap} from './heatmap';
7
+ import {RTTModifier, PostProcessModifier} from './post-process-utils';
8
+ import QuadbinTileLayer, {QuadbinTileLayerProps} from './quadbin-tile-layer';
9
+ import {TilejsonPropType} from './utils';
10
+ import {TilejsonResult} from '../sources';
11
+ import {_Tile2DHeader as Tile2DHeader} from '@deck.gl/geo-layers';
12
+
13
+ /**
14
+ * Computes the unit density (inverse of cell area)
15
+ */
16
+ function unitDensityForCell(cell: bigint) {
17
+ const cellResolution = Number(getResolution(cell));
18
+ return Math.pow(4.0, cellResolution);
19
+ }
20
+
21
+ // Modified polygon layer to draw offscreen and output value expected by heatmap
22
+ class RTTSolidPolygonLayer extends RTTModifier(SolidPolygonLayer) {
23
+ static layerName = 'RTTSolidPolygonLayer';
24
+
25
+ getShaders(type) {
26
+ const shaders = super.getShaders(type);
27
+ shaders.inject = {
28
+ 'vs:#decl': `
29
+ uniform float densityFactor;
30
+ `,
31
+ 'vs:#main-end': `
32
+ // Value from getWeight accessor
33
+ float weight = elevations;
34
+
35
+ // Keep "power" delivered to screen constant when tiles update
36
+ // by outputting normalized density
37
+ weight *= densityFactor;
38
+
39
+ // Pack float into 3 channels to pass to heatmap shader
40
+ // SCALE value important, as we don't want to saturate
41
+ // but also want enough definition to avoid banding
42
+ const vec3 SHIFT = vec3(1.0, 256.0, 256.0 * 256.0);
43
+ const float MAX_VAL = SHIFT.z * 255.0;
44
+ const float SCALE = MAX_VAL / 8.0;
45
+ weight *= SCALE;
46
+ weight = clamp(weight, 0.0, MAX_VAL);
47
+ vColor = vec4(mod(vec3(weight, floor(weight / SHIFT.yz)), 256.0), 255.0) / 255.0;
48
+ `
49
+ };
50
+ return shaders;
51
+ }
52
+
53
+ draw(this, opts: any) {
54
+ const cell = this.props!.data[0];
55
+ const maxDensity = this.props.elevationScale;
56
+ const densityFactor = unitDensityForCell(cell.id) / maxDensity;
57
+ for (const model of this.state.models) {
58
+ model.setUniforms({densityFactor});
59
+ }
60
+
61
+ super.draw(opts);
62
+ }
63
+ }
64
+
65
+ // Modify QuadbinTileLayer to apply heatmap post process effect
66
+ const PostProcessQuadbinTileLayer = PostProcessModifier(QuadbinTileLayer, heatmap);
67
+
68
+ const defaultProps: DefaultProps<HeatmapTileLayerProps> = {
69
+ data: TilejsonPropType,
70
+ getWeight: {type: 'accessor', value: 1},
71
+ onMaxDensityChange: {type: 'function', optional: true, value: null},
72
+ colorDomain: {type: 'array', value: [0, 1]},
73
+ intensity: {type: 'number', value: 1},
74
+ radiusPixels: {type: 'number', min: 0, max: 100, value: 20}
75
+ };
76
+
77
+ /** All properties supported by HeatmapTileLayer. */
78
+ export type HeatmapTileLayerProps<DataT = unknown> = _HeatmapTileLayerProps<DataT> &
79
+ CompositeLayerProps & {
80
+ data: null | TilejsonResult | Promise<TilejsonResult>;
81
+ };
82
+
83
+ /** Properties added by HeatmapTileLayer. */
84
+ type _HeatmapTileLayerProps<DataT> = QuadbinTileLayerProps<DataT> &
85
+ HeatmapProps & {
86
+ /**
87
+ * The weight of each object.
88
+ *
89
+ * @default 1
90
+ */
91
+ getWeight?: Accessor<DataT, number>;
92
+
93
+ /** Called when maximum density in displayed tiles changes. */
94
+ onMaxDensityChange?: ((maxDensity: number) => void) | null;
95
+ };
96
+
97
+ class HeatmapTileLayer<DataT = any, ExtraProps extends {} = {}> extends CompositeLayer<
98
+ ExtraProps & Required<_HeatmapTileLayerProps<DataT>>
99
+ > {
100
+ static layerName = 'HeatmapTileLayer';
101
+ static defaultProps = defaultProps;
102
+
103
+ state!: {
104
+ isLoaded: boolean;
105
+ tiles: Set<Tile2DHeader>;
106
+ viewportChanged?: boolean;
107
+ };
108
+ initializeState() {
109
+ this.state = {
110
+ isLoaded: false,
111
+ tiles: new Set(),
112
+ viewportChanged: false
113
+ };
114
+ }
115
+
116
+ shouldUpdateState({changeFlags}): boolean {
117
+ const {viewportChanged} = changeFlags;
118
+ this.setState({viewportChanged});
119
+ return changeFlags.somethingChanged;
120
+ }
121
+
122
+ renderLayers(): Layer {
123
+ const {
124
+ data,
125
+ getWeight,
126
+ colorDomain,
127
+ colorRange,
128
+ intensity,
129
+ radiusPixels,
130
+ _subLayerProps,
131
+ updateTriggers,
132
+ onMaxDensityChange,
133
+ onViewportLoad,
134
+ onTileLoad,
135
+ onTileUnload,
136
+ ...tileLayerProps
137
+ } = this.props;
138
+
139
+ // Inject modified polygon layer as sublayer into TileLayer
140
+ const subLayerProps = {
141
+ ..._subLayerProps,
142
+ cell: {
143
+ ..._subLayerProps?.cell,
144
+ _subLayerProps: {
145
+ ..._subLayerProps?.cell?._subLayerProps,
146
+ fill: {
147
+ ..._subLayerProps?.cell?._subLayerProps?.fill,
148
+ type: RTTSolidPolygonLayer
149
+ }
150
+ }
151
+ }
152
+ };
153
+
154
+ let tileZ = 0;
155
+ let maxDensity = 0;
156
+ const tiles = [...this.state.tiles].filter(t => t.isVisible && t.data);
157
+ for (const tile of tiles) {
158
+ const cell = tile.data[0];
159
+ const unitDensity = unitDensityForCell(cell.id);
160
+ maxDensity = Math.max(tile.userData!.maxWeight * unitDensity, maxDensity);
161
+ tileZ = Math.max(tile.zoom, tileZ);
162
+ }
163
+
164
+ // Between zoom levels the max density will change, but it isn't possible to know by what factor. Uniform data distributions lead to a factor of 4, while very localized data gives 1. As a heurstic estimate with a value inbetween (2) to make the transitions less obvious.
165
+ const overzoom = this.context.viewport.zoom - tileZ;
166
+ const estimatedMaxDensity = maxDensity * Math.pow(2, overzoom);
167
+
168
+ maxDensity = estimatedMaxDensity;
169
+ if (typeof onMaxDensityChange === 'function') {
170
+ onMaxDensityChange(maxDensity);
171
+ }
172
+ return new PostProcessQuadbinTileLayer(
173
+ tileLayerProps as Omit<QuadbinTileLayerProps, 'data'>,
174
+ this.getSubLayerProps({
175
+ id: 'heatmap',
176
+ data,
177
+
178
+ // Re-use existing props to pass down values to sublayer
179
+ // TODO replace with custom layer
180
+ getFillColor: 0,
181
+ getElevation: getWeight,
182
+ elevationScale: maxDensity,
183
+
184
+ colorDomain,
185
+
186
+ colorRange,
187
+ radiusPixels,
188
+ intensity,
189
+ _subLayerProps: subLayerProps,
190
+ refinementStrategy: 'no-overlap',
191
+
192
+ // Disable line rendering
193
+ extruded: false,
194
+ stroked: false,
195
+
196
+ updateTriggers: {
197
+ getElevation: updateTriggers.getWeight
198
+ },
199
+
200
+ // Tile stats
201
+ onViewportLoad: tiles => {
202
+ this.setState({isLoaded: true});
203
+ if (typeof onViewportLoad === 'function') {
204
+ onViewportLoad(tiles);
205
+ }
206
+ },
207
+ onTileLoad: (tile: Tile2DHeader) => {
208
+ let maxWeight = -Infinity;
209
+ if (typeof getWeight !== 'function') {
210
+ maxWeight = getWeight;
211
+ } else if (tile.content) {
212
+ for (const d of tile.content) {
213
+ maxWeight = Math.max(getWeight(d, {} as any), maxWeight);
214
+ }
215
+ }
216
+ tile.userData = {maxWeight};
217
+
218
+ this.state.tiles.add(tile);
219
+
220
+ if (typeof onTileLoad === 'function') {
221
+ onTileLoad(tile);
222
+ }
223
+ },
224
+ onTileUnload: (tile: Tile2DHeader) => {
225
+ this.state.tiles.delete(tile);
226
+ if (typeof onTileUnload === 'function') {
227
+ onTileUnload(tile);
228
+ }
229
+ },
230
+ transitions: {elevationScale: {type: 'spring', stiffness: 0.3, damping: 0.5}}
231
+ })
232
+ );
233
+ }
234
+ }
235
+
236
+ export default HeatmapTileLayer;
@@ -1,5 +1,4 @@
1
1
  import type {ShaderPass} from '@luma.gl/shadertools';
2
- import {random} from '@luma.gl/shadertools';
3
2
  import {Color} from '@deck.gl/core';
4
3
  const glsl = (s: TemplateStringsArray) => `${s}`;
5
4
 
@@ -21,11 +20,10 @@ uniform heatmapUniforms {
21
20
  vec3 color4;
22
21
  vec3 color5;
23
22
  vec3 color6;
23
+ float intensity;
24
24
  float opacity;
25
25
  } heatmap;
26
26
 
27
- // Controls quality of heatmap, larger values increase quality at expense of performance
28
- const float SUPPORT = 8.0;
29
27
  const vec4 STOPS = vec4(0.2, 0.4, 0.6, 0.8);
30
28
 
31
29
  vec3 colorGradient(float value) {
@@ -44,20 +42,18 @@ vec3 colorGradient(float value) {
44
42
  } else if (value < STOPS.w) {
45
43
  range = STOPS.zw;
46
44
  c1 = heatmap.color4; c2 = heatmap.color5;
47
- } else if (value < 1.0 ) {
45
+ } else {
48
46
  range = vec2(STOPS.w, 1.0);
49
47
  c1 = heatmap.color5; c2 = heatmap.color6;
50
- } else {
51
- // Fade out to white
52
- range = vec2(1.0, 10.0);
53
- c1 = heatmap.color6; c2 = vec3(255.0);
54
48
  }
55
49
 
56
- float f = (value - range.x) / (range.y - range.x);
50
+ float f = (clamp(value, 0.0, 1.0) - range.x) / (range.y - range.x);
57
51
  return mix(c1, c2, f) / 255.0;
58
52
  }
59
53
 
60
54
  const vec3 SHIFT = vec3(1.0, 256.0, 256.0 * 256.0);
55
+ const float MAX_VAL = SHIFT.z * 255.0;
56
+ const float SCALE = MAX_VAL / 8.0;
61
57
  vec4 pack(float value) {
62
58
  return vec4(mod(vec3(value, floor(value / SHIFT.yz)), 256.0), 255.0) / 255.0;
63
59
  }
@@ -69,16 +65,15 @@ vec4 heatmap_sampleColor(sampler2D source, vec2 texSize, vec2 texCoord) {
69
65
  bool firstPass = (heatmap.delta.y < 0.5);
70
66
  float accumulator = 0.0;
71
67
 
72
- // Randomize the lookup values to hide the fixed number of samples
73
- float offset = 0.5 * random(vec3(12.9898, 78.233, 151.7182), 0.0);
68
+ // Controls quality of heatmap, larger values increase quality at expense of performance
69
+ float SUPPORT = clamp(heatmap.radiusPixels / 2.0, 8.0, 32.0);
74
70
 
75
71
  // Gaussian normalization parameters
76
- const float sigma = SUPPORT / 3.0;
77
- const float a = -0.5 / (sigma * sigma);
78
- const float w0 = 0.3989422804014327 / sigma; // 1D normalization
79
-
72
+ float sigma = SUPPORT / 3.0;
73
+ float a = -0.5 / (sigma * sigma);
74
+ float w0 = 0.3989422804014327 / sigma; // 1D normalization
80
75
  for (float t = -SUPPORT; t <= SUPPORT; t++) {
81
- vec2 percent = (t * heatmap.delta + offset - 0.5) / SUPPORT;
76
+ vec2 percent = (t * heatmap.delta - 0.5) / SUPPORT;
82
77
  vec2 delta = percent * heatmap.radiusPixels / texSize;
83
78
  vec4 offsetColor = texture(source, texCoord + delta);
84
79
 
@@ -95,8 +90,18 @@ vec4 heatmap_sampleColor(sampler2D source, vec2 texSize, vec2 texCoord) {
95
90
  return pack(accumulator);
96
91
  }
97
92
 
93
+ // Undo scaling to obtain normalized density
94
+ float density = 10.0 * heatmap.intensity * accumulator / SCALE;
95
+
96
+ // Domain also in normalized density units
97
+ vec2 domain = heatmap.colorDomain;
98
+
98
99
  // Apply domain
99
- float f = (accumulator - heatmap.colorDomain[0]) / (heatmap.colorDomain[1] - heatmap.colorDomain[0]);
100
+ float f = (density - domain[0]) / (domain[1] - domain[0]);
101
+
102
+ // sqrt/log scaling??
103
+ // float f = (log(density) - log(domain[0] + 1.0)) / (log(domain[1] + 1.0) - log(domain[0] + 1.0));
104
+ // f = sqrt(f);
100
105
 
101
106
  // Color map
102
107
  vec4 color = vec4(0.0);
@@ -138,6 +143,10 @@ export type HeatmapProps = {
138
143
  * @default `6-class YlOrRd` - [colorbrewer](http://colorbrewer2.org/#type=sequential&scheme=YlOrRd&n=6)
139
144
  */
140
145
  colorRange: Color[];
146
+ /**
147
+ * Value that is multiplied with the total weight at a pixel to obtain the final weight. A value larger than 1 biases the output color towards the higher end of the spectrum, and a value less than 1 biases the output color towards the lower end of the spectrum.
148
+ */
149
+ intensity?: number;
141
150
  opacity: number;
142
151
  };
143
152
 
@@ -151,6 +160,7 @@ export type HeatmapUniforms = {
151
160
  color4?: [number, number, number];
152
161
  color5?: [number, number, number];
153
162
  color6?: [number, number, number];
163
+ intensity: number;
154
164
  opacity?: number;
155
165
  };
156
166
 
@@ -166,6 +176,7 @@ export const heatmap: ShaderPass<HeatmapProps, HeatmapUniforms> = {
166
176
  color4: {value: [0, 0, 0]},
167
177
  color5: {value: [0, 0, 0]},
168
178
  color6: {value: [0, 0, 0]},
179
+ intensity: {value: 1, min: 0.1, max: 10},
169
180
  opacity: {value: 1, min: 0, max: 1}
170
181
  },
171
182
  uniformTypes: {
@@ -178,6 +189,7 @@ export const heatmap: ShaderPass<HeatmapProps, HeatmapUniforms> = {
178
189
  color4: 'vec3<f32>',
179
190
  color5: 'vec3<f32>',
180
191
  color6: 'vec3<f32>',
192
+ intensity: 'f32',
181
193
  opacity: 'f32'
182
194
  },
183
195
  getUniforms: opts => {
@@ -186,6 +198,7 @@ export const heatmap: ShaderPass<HeatmapProps, HeatmapUniforms> = {
186
198
  colorRange = defaultColorRange,
187
199
  radiusPixels = 20,
188
200
  colorDomain = [0, 1],
201
+ intensity = 1,
189
202
  opacity = 1
190
203
  } = opts as HeatmapProps & {delta: [number, number]};
191
204
  const [color1, color2, color3, color4, color5, color6] = colorRange;
@@ -199,10 +212,10 @@ export const heatmap: ShaderPass<HeatmapProps, HeatmapUniforms> = {
199
212
  color6,
200
213
  radiusPixels,
201
214
  colorDomain,
215
+ intensity,
202
216
  opacity
203
217
  };
204
218
  },
205
- dependencies: [random],
206
219
  fs,
207
220
  passes: [
208
221
  {sampler: true, uniforms: {delta: [1, 0]}},
@@ -14,9 +14,6 @@ import {
14
14
  _TileLoadProps as TileLoadProps
15
15
  } from '@deck.gl/geo-layers';
16
16
  import {GeoJsonLayer} from '@deck.gl/layers';
17
- import {binaryToGeojson} from '@loaders.gl/gis';
18
- import type {BinaryFeatureCollection} from '@loaders.gl/schema';
19
- import type {Feature, Geometry} from 'geojson';
20
17
 
21
18
  import type {TilejsonResult} from '../sources/types';
22
19
  import {TilejsonPropType, injectAccessToken, mergeBoundaryData} from './utils';
@@ -148,16 +145,9 @@ export default class VectorTileLayer<
148
145
  return subLayer;
149
146
  }
150
147
 
151
- getPickingInfo(params) {
152
- const info = super.getPickingInfo(params);
153
-
154
- if (this.state.binary && info.index !== -1) {
155
- const {data} = params.sourceLayer!.props;
156
- info.object = binaryToGeojson(data as BinaryFeatureCollection, {
157
- globalFeatureId: info.index
158
- }) as Feature<Geometry, FeaturePropertiesT>;
159
- }
160
-
161
- return info;
148
+ protected override _isWGS84(): boolean {
149
+ // CARTO binary tile coordinates are [lng, lat], not tile-relative like MVT.
150
+ if (this.state.mvt) return super._isWGS84();
151
+ return true;
162
152
  }
163
153
  }
@@ -1,12 +1,17 @@
1
1
  import {baseSource} from './base-source';
2
- import type {SourceOptions, TilejsonResult, TilesetSourceOptions} from './types';
2
+ import type {FilterOptions, SourceOptions, TilejsonResult, TilesetSourceOptions} from './types';
3
3
 
4
- export type RasterSourceOptions = SourceOptions & TilesetSourceOptions;
5
- type UrlParameters = {name: string};
4
+ export type RasterSourceOptions = SourceOptions & TilesetSourceOptions & FilterOptions;
5
+ type UrlParameters = {
6
+ name: string;
7
+ filters?: Record<string, unknown>;
8
+ };
6
9
 
7
10
  export const rasterSource = async function (options: RasterSourceOptions): Promise<TilejsonResult> {
8
- const {tableName} = options;
11
+ const {tableName, filters} = options;
9
12
  const urlParameters: UrlParameters = {name: tableName};
10
-
13
+ if (filters) {
14
+ urlParameters.filters = filters;
15
+ }
11
16
  return baseSource<UrlParameters>('raster', options, urlParameters) as Promise<TilejsonResult>;
12
17
  };
@@ -1,24 +0,0 @@
1
- import { Accessor, CompositeLayer, CompositeLayerProps, DefaultProps, Layer } from '@deck.gl/core';
2
- import { HeatmapProps } from "./heatmap.js";
3
- import { QuadbinTileLayerProps } from "./quadbin-tile-layer.js";
4
- import { TilejsonResult } from "../sources.js";
5
- /** All properties supported by QuadbinHeatmapTileLayer. */
6
- export type QuadbinHeatmapTileLayerProps<DataT = unknown> = _QuadbinHeatmapTileLayerProps<DataT> & CompositeLayerProps & {
7
- data: null | TilejsonResult | Promise<TilejsonResult>;
8
- };
9
- /** Properties added by QuadbinHeatmapTileLayer. */
10
- type _QuadbinHeatmapTileLayerProps<DataT> = QuadbinTileLayerProps<DataT> & HeatmapProps & {
11
- /**
12
- * The weight of each object.
13
- *
14
- * @default 1
15
- */
16
- getWeight?: Accessor<DataT, number>;
17
- };
18
- declare class QuadbinHeatmapTileLayer<DataT = any, ExtraProps extends {} = {}> extends CompositeLayer<ExtraProps & Required<_QuadbinHeatmapTileLayerProps<DataT>>> {
19
- static layerName: string;
20
- static defaultProps: DefaultProps<QuadbinHeatmapTileLayerProps<unknown>>;
21
- renderLayers(): Layer;
22
- }
23
- export default QuadbinHeatmapTileLayer;
24
- //# sourceMappingURL=quadbin-heatmap-tile-layer.d.ts.map