@deck.gl/carto 9.2.0-alpha.2 → 9.2.0-beta.1

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 (42) hide show
  1. package/dist/api/parse-map.js +1 -1
  2. package/dist/api/parse-map.js.map +1 -1
  3. package/dist/cartoPropertiesTile-worker.js +1 -1
  4. package/dist/cartoRasterTile-worker.js +1 -1
  5. package/dist/cartoSpatialTile-worker.js +1 -1
  6. package/dist/cartoVectorTile-worker.js +1 -1
  7. package/dist/dist.dev.js +67 -49
  8. package/dist/index.cjs +66 -48
  9. package/dist/index.cjs.map +3 -3
  10. package/dist/layers/h3-tileset-2d.d.ts.map +1 -1
  11. package/dist/layers/h3-tileset-2d.js +16 -5
  12. package/dist/layers/h3-tileset-2d.js.map +1 -1
  13. package/dist/layers/heatmap-tile-layer.d.ts +3 -1
  14. package/dist/layers/heatmap-tile-layer.d.ts.map +1 -1
  15. package/dist/layers/heatmap-tile-layer.js +69 -35
  16. package/dist/layers/heatmap-tile-layer.js.map +1 -1
  17. package/dist/layers/heatmap.d.ts +1 -1
  18. package/dist/layers/heatmap.d.ts.map +1 -1
  19. package/dist/layers/heatmap.js +3 -0
  20. package/dist/layers/heatmap.js.map +1 -1
  21. package/dist/layers/post-process-utils.d.ts.map +1 -1
  22. package/dist/layers/post-process-utils.js +2 -1
  23. package/dist/layers/post-process-utils.js.map +1 -1
  24. package/dist/layers/raster-layer.d.ts.map +1 -1
  25. package/dist/layers/raster-layer.js +1 -11
  26. package/dist/layers/raster-layer.js.map +1 -1
  27. package/dist/layers/schema/carto-properties-tile-loader.js +1 -1
  28. package/dist/layers/schema/carto-properties-tile-loader.js.map +1 -1
  29. package/dist/layers/schema/carto-raster-tile-loader.js +1 -1
  30. package/dist/layers/schema/carto-raster-tile-loader.js.map +1 -1
  31. package/dist/layers/schema/carto-spatial-tile-loader.js +1 -1
  32. package/dist/layers/schema/carto-spatial-tile-loader.js.map +1 -1
  33. package/dist/layers/schema/carto-vector-tile-loader.js +1 -1
  34. package/dist/layers/schema/carto-vector-tile-loader.js.map +1 -1
  35. package/dist.min.js +12 -9
  36. package/package.json +5 -5
  37. package/src/api/parse-map.ts +1 -1
  38. package/src/layers/h3-tileset-2d.ts +18 -5
  39. package/src/layers/heatmap-tile-layer.ts +78 -35
  40. package/src/layers/heatmap.ts +3 -0
  41. package/src/layers/post-process-utils.ts +2 -1
  42. package/src/layers/raster-layer.ts +1 -12
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.2.0-alpha.2",
6
+ "version": "9.2.0-beta.1",
7
7
  "publishConfig": {
8
8
  "access": "public"
9
9
  },
@@ -49,8 +49,8 @@
49
49
  "@loaders.gl/mvt": "^4.2.0",
50
50
  "@loaders.gl/schema": "^4.2.0",
51
51
  "@loaders.gl/tiles": "^4.2.0",
52
- "@luma.gl/core": "^9.1.9",
53
- "@luma.gl/shadertools": "^9.1.9",
52
+ "@luma.gl/core": "^9.2.0-alpha.5",
53
+ "@luma.gl/shadertools": "^9.2.0-alpha.5",
54
54
  "@math.gl/web-mercator": "^4.1.0",
55
55
  "@types/d3-array": "^3.0.2",
56
56
  "@types/d3-color": "^1.4.2",
@@ -73,7 +73,7 @@
73
73
  "@deck.gl/geo-layers": "^9.1.0",
74
74
  "@deck.gl/layers": "^9.1.0",
75
75
  "@loaders.gl/core": "^4.2.0",
76
- "@luma.gl/core": "^9.1.9"
76
+ "@luma.gl/core": "^9.2.0-alpha.5"
77
77
  },
78
- "gitHead": "f9ca91bb15011ff5552ca8966b4207ada03a08fc"
78
+ "gitHead": "84407defece157d45954f66cf191cca3c596ee99"
79
79
  }
@@ -92,7 +92,7 @@ function createParametersProp(layerBlending: string, parameters: ColorParameters
92
92
  parameters.blendColorOperation = parameters.blendAlphaOperation = 'add';
93
93
  } else if (layerBlending === 'subtractive') {
94
94
  parameters.blendColorSrcFactor = 'one';
95
- parameters.blendColorDstFactor = 'one-minus-dst-color';
95
+ parameters.blendColorDstFactor = 'one-minus-dst';
96
96
  parameters.blendAlphaSrcFactor = 'src-alpha';
97
97
  parameters.blendAlphaDstFactor = 'dst-alpha';
98
98
  parameters.blendColorOperation = 'subtract';
@@ -19,11 +19,19 @@ export type H3TileIndex = {i: string};
19
19
 
20
20
  const MAX_LATITUDE = 85.051128;
21
21
 
22
- // `polygonToCells()` fills based on hexagon center, this function will
23
- // pad the bounds such that all cells that overlap the bounds will be included
22
+ /**
23
+ * `polygonToCells()` fills based on hexagon center, this function will
24
+ * pad the bounds such that all cells that overlap the bounds will be included.
25
+ *
26
+ * @param bbox - The bounding box to pad.
27
+ * @param resolution - The resolution of the hexagons.
28
+ * @param scale - The scale of the buffer. 1 is to pad by the max edge length of the tile cell.
29
+ * @returns The padded bounding box.
30
+ */
24
31
  function padBoundingBox(
25
32
  {west, north, east, south}: GeoBoundingBox,
26
- resolution: number
33
+ resolution: number,
34
+ scale: number = 1.0
27
35
  ): GeoBoundingBox {
28
36
  const corners = [
29
37
  [north, east],
@@ -35,7 +43,7 @@ function padBoundingBox(
35
43
  const cornerEdgeLengths = cornerCells.map(
36
44
  c => (Math.max(...originToDirectedEdges(c).map(e => edgeLength(e, UNITS.rads))) * 180) / Math.PI
37
45
  );
38
- const bufferLat = Math.max(...cornerEdgeLengths);
46
+ const bufferLat = Math.max(...cornerEdgeLengths) * scale;
39
47
  const bufferLon = Math.min(180, bufferLat / Math.cos((((north + south) / 2) * Math.PI) / 180));
40
48
 
41
49
  return {
@@ -84,7 +92,12 @@ function tileToBoundingBox(index: string): GeoBoundingBox {
84
92
  const south = Math.min(...latitudes);
85
93
  const east = Math.max(...longitudes);
86
94
  const north = Math.max(...latitudes);
87
- return {west, south, east, north};
95
+ const bbox = {west, south, east, north};
96
+
97
+ // H3 child cells extend beyond their parent's boundary forming a "snowflake"
98
+ // fractal pattern. The required buffer is approximately 10% of the
99
+ // edge length of the tile cell, add a bit more to be safe.
100
+ return padBoundingBox(bbox, getResolution(index), 0.12);
88
101
  }
89
102
 
90
103
  // Resolution conversion function. Takes a WebMercatorViewport and returns
@@ -6,12 +6,14 @@
6
6
 
7
7
  import type {ShaderModule} from '@luma.gl/shadertools';
8
8
  import {getResolution} from 'quadbin';
9
+ import {getResolution as getH3Resolution, getNumCells} from 'h3-js';
9
10
 
10
11
  import {
11
12
  Accessor,
12
13
  Color,
13
14
  CompositeLayer,
14
15
  CompositeLayerProps,
16
+ _deepEqual as deepEqual,
15
17
  DefaultProps,
16
18
  Layer,
17
19
  UpdateParameters
@@ -21,6 +23,7 @@ import {SolidPolygonLayer} from '@deck.gl/layers';
21
23
  import {HeatmapProps, heatmap} from './heatmap';
22
24
  import {RTTModifier, PostProcessModifier} from './post-process-utils';
23
25
  import QuadbinTileLayer, {QuadbinTileLayerProps} from './quadbin-tile-layer';
26
+ import H3TileLayer, {H3TileLayerProps} from './h3-tile-layer';
24
27
  import {TilejsonPropType} from './utils';
25
28
  import {TilejsonResult} from '@carto/api-client';
26
29
  import {_Tile2DHeader as Tile2DHeader} from '@deck.gl/geo-layers';
@@ -37,7 +40,9 @@ const defaultColorRange: Color[] = [
37
40
 
38
41
  const TEXTURE_PROPS: TextureProps = {
39
42
  format: 'rgba8unorm',
40
- mipmaps: false,
43
+ dimension: '2d',
44
+ width: 1,
45
+ height: 1,
41
46
  sampler: {
42
47
  minFilter: 'linear',
43
48
  magFilter: 'linear',
@@ -46,13 +51,23 @@ const TEXTURE_PROPS: TextureProps = {
46
51
  }
47
52
  };
48
53
  /**
49
- * Computes the unit density (inverse of cell area)
54
+ * Computes the unit density for Quadbin cells.
55
+ * The unit density is the number of cells needed to cover the Earth's surface at a given resolution. It is inversely proportional to the cell area.
50
56
  */
51
- function unitDensityForCell(cell: bigint) {
57
+ function unitDensityForQuadbinCell(cell: bigint) {
52
58
  const cellResolution = Number(getResolution(cell));
53
59
  return Math.pow(4.0, cellResolution);
54
60
  }
55
61
 
62
+ /**
63
+ * Computes the unit density for H3 cells.
64
+ * The unit density is the number of cells needed to cover the Earth's surface at a given resolution. It is inversely proportional to the cell area.
65
+ */
66
+ function unitDensityForH3Cell(cellId: string) {
67
+ const cellResolution = Number(getH3Resolution(cellId));
68
+ return getNumCells(cellResolution);
69
+ }
70
+
56
71
  /**
57
72
  * Converts a colorRange array to a flat array with 4 components per color
58
73
  */
@@ -118,12 +133,15 @@ class RTTSolidPolygonLayer extends RTTModifier(SolidPolygonLayer) {
118
133
 
119
134
  draw(this, opts: any) {
120
135
  const cell = this.props!.data[0];
121
- const maxDensity = this.props.elevationScale;
122
- const densityProps: DensityProps = {
123
- factor: unitDensityForCell(cell.id) / maxDensity
124
- };
125
- for (const model of this.state.models) {
126
- model.shaderInputs.setProps({density: densityProps});
136
+ if (cell) {
137
+ const maxDensity = this.props.elevationScale;
138
+ const {scheme} = this.parent.parent.parent.parent.parent.state;
139
+ const unitDensity =
140
+ scheme === 'h3' ? unitDensityForH3Cell(cell.id) : unitDensityForQuadbinCell(cell.id);
141
+ const densityProps: DensityProps = {factor: unitDensity / maxDensity};
142
+ for (const model of this.state.models) {
143
+ model.shaderInputs.setProps({density: densityProps});
144
+ }
127
145
  }
128
146
 
129
147
  super.draw(opts);
@@ -133,6 +151,9 @@ class RTTSolidPolygonLayer extends RTTModifier(SolidPolygonLayer) {
133
151
  // Modify QuadbinTileLayer to apply heatmap post process effect
134
152
  const PostProcessQuadbinTileLayer = PostProcessModifier(QuadbinTileLayer, heatmap);
135
153
 
154
+ // Modify H3TileLayer to apply heatmap post process effect
155
+ const PostProcessH3TileLayer = PostProcessModifier(H3TileLayer, heatmap);
156
+
136
157
  const defaultProps: DefaultProps<HeatmapTileLayerProps> = {
137
158
  data: TilejsonPropType,
138
159
  getWeight: {type: 'accessor', value: 1},
@@ -150,7 +171,7 @@ export type HeatmapTileLayerProps<DataT = unknown> = _HeatmapTileLayerProps<Data
150
171
  };
151
172
 
152
173
  /** Properties added by HeatmapTileLayer. */
153
- type _HeatmapTileLayerProps<DataT> = QuadbinTileLayerProps<DataT> &
174
+ type _HeatmapTileLayerProps<DataT> = (QuadbinTileLayerProps<DataT> | H3TileLayerProps<DataT>) &
154
175
  HeatmapProps & {
155
176
  /**
156
177
  * Specified as an array of colors [color1, color2, ...].
@@ -179,12 +200,14 @@ class HeatmapTileLayer<DataT = any, ExtraProps extends {} = {}> extends Composit
179
200
  state!: {
180
201
  colorTexture?: Texture;
181
202
  isLoaded: boolean;
203
+ scheme: string | null;
182
204
  tiles: Set<Tile2DHeader>;
183
205
  viewportChanged?: boolean;
184
206
  };
185
207
  initializeState() {
186
208
  this.state = {
187
209
  isLoaded: false,
210
+ scheme: null,
188
211
  tiles: new Set(),
189
212
  viewportChanged: false
190
213
  };
@@ -199,9 +222,15 @@ class HeatmapTileLayer<DataT = any, ExtraProps extends {} = {}> extends Composit
199
222
  updateState(opts: UpdateParameters<this>) {
200
223
  const {props, oldProps} = opts;
201
224
  super.updateState(opts);
202
- if (props.colorRange !== oldProps.colorRange) {
225
+ if (!deepEqual(props.colorRange, oldProps.colorRange, 2)) {
203
226
  this._updateColorTexture(opts);
204
227
  }
228
+
229
+ const scheme = props.data && 'scheme' in props.data ? props.data.scheme : null;
230
+ if (this.state.scheme !== scheme) {
231
+ this.setState({scheme});
232
+ this.state.tiles.clear();
233
+ }
205
234
  }
206
235
 
207
236
  renderLayers(): Layer {
@@ -220,15 +249,18 @@ class HeatmapTileLayer<DataT = any, ExtraProps extends {} = {}> extends Composit
220
249
  ...tileLayerProps
221
250
  } = this.props;
222
251
 
252
+ const isH3 = this.state.scheme === 'h3';
253
+
254
+ const cellLayerName = isH3 ? 'hexagon-cell-hifi' : 'cell';
223
255
  // Inject modified polygon layer as sublayer into TileLayer
224
256
  const subLayerProps = {
225
257
  ..._subLayerProps,
226
- cell: {
227
- ..._subLayerProps?.cell,
258
+ [cellLayerName]: {
259
+ ..._subLayerProps?.[cellLayerName],
228
260
  _subLayerProps: {
229
- ..._subLayerProps?.cell?._subLayerProps,
261
+ ..._subLayerProps?.[cellLayerName]?._subLayerProps,
230
262
  fill: {
231
- ..._subLayerProps?.cell?._subLayerProps?.fill,
263
+ ..._subLayerProps?.[cellLayerName]?._subLayerProps?.fill,
232
264
  type: RTTSolidPolygonLayer
233
265
  }
234
266
  }
@@ -246,21 +278,37 @@ class HeatmapTileLayer<DataT = any, ExtraProps extends {} = {}> extends Composit
246
278
 
247
279
  for (const tile of tiles) {
248
280
  const cell = tile.content[0];
249
- const unitDensity = unitDensityForCell(cell.id);
281
+ const unitDensity = isH3 ? unitDensityForH3Cell(cell.id) : unitDensityForQuadbinCell(cell.id);
250
282
  maxDensity = Math.max(tile.userData!.maxWeight * unitDensity, maxDensity);
251
283
  tileZ = Math.max(tile.zoom, tileZ);
252
284
  }
253
285
 
254
- // 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.
255
- const overzoom = this.context.viewport.zoom - tileZ;
256
- const estimatedMaxDensity = maxDensity * Math.pow(2, overzoom);
286
+ // Between zoom levels the max density will change, but it isn't possible to know by what factor.
287
+ // As a heuristic, an estimatedGrowthFactor makes the transitions less obvious.
288
+ // For quadbin, uniform data distributions lead to an estimatedGrowthFactor of 4, while very localized data gives 1.
289
+ // For H3 the same logic applies but the aperture is 7, rather than 4, so a slightly higher estimatedGrowthFactor is used.
290
+ let overzoom: number;
291
+ let estimatedGrowthFactor: number;
292
+ if (isH3) {
293
+ // For H3, we need to account for the viewport zoom to H3 resolution mapping (see getHexagonResolution())
294
+ overzoom = (2 / 3) * this.context.viewport.zoom - tileZ - 2.25;
295
+ estimatedGrowthFactor = 2.2;
296
+ } else {
297
+ overzoom = this.context.viewport.zoom - tileZ;
298
+ estimatedGrowthFactor = 2;
299
+ }
257
300
 
258
- maxDensity = estimatedMaxDensity;
301
+ maxDensity = maxDensity * Math.pow(estimatedGrowthFactor, overzoom);
259
302
  if (typeof onMaxDensityChange === 'function') {
260
303
  onMaxDensityChange(maxDensity);
261
304
  }
262
- return new PostProcessQuadbinTileLayer(
263
- tileLayerProps as Omit<QuadbinTileLayerProps, 'data'>,
305
+ const PostProcessTileLayer = isH3 ? PostProcessH3TileLayer : PostProcessQuadbinTileLayer;
306
+ const layerProps = isH3
307
+ ? (tileLayerProps as Omit<H3TileLayerProps, 'data'>)
308
+ : (tileLayerProps as Omit<QuadbinTileLayerProps, 'data'>);
309
+
310
+ return new PostProcessTileLayer(
311
+ layerProps,
264
312
  this.getSubLayerProps({
265
313
  id: 'heatmap',
266
314
  data,
@@ -328,19 +376,14 @@ class HeatmapTileLayer<DataT = any, ExtraProps extends {} = {}> extends Composit
328
376
  let {colorTexture} = this.state;
329
377
  const colors = colorRangeToFlatArray(colorRange);
330
378
 
331
- if (colorTexture && colorTexture?.width === colorRange.length) {
332
- // TODO(v9): Unclear whether `setSubImageData` is a public API, or what to use if not.
333
- (colorTexture as any).setTexture2DData({data: colors});
334
- } else {
335
- colorTexture?.destroy();
336
- // @ts-ignore TODO v9.1
337
- colorTexture = this.context.device.createTexture({
338
- ...TEXTURE_PROPS,
339
- data: colors,
340
- width: colorRange.length,
341
- height: 1
342
- });
343
- }
379
+ colorTexture?.destroy();
380
+ colorTexture = this.context.device.createTexture({
381
+ ...TEXTURE_PROPS,
382
+ data: colors,
383
+ width: colorRange.length,
384
+ height: 1
385
+ });
386
+
344
387
  this.setState({colorTexture});
345
388
  }
346
389
  }
@@ -89,6 +89,9 @@ vec4 heatmap_sampleColor(sampler2D source, vec2 texSize, vec2 texCoord) {
89
89
  color.a = pow(color.a, 1.0 / 2.2);
90
90
  color.a *= heatmap.opacity;
91
91
 
92
+ // Use premultiplied alpha for compatibility with blending in ScreenPass
93
+ color.rgb *= color.a;
94
+
92
95
  return color;
93
96
  }
94
97
  `;
@@ -17,7 +17,8 @@ import {
17
17
 
18
18
  const TEXTURE_PROPS: TextureProps = {
19
19
  format: 'rgba8unorm',
20
- mipmaps: false,
20
+ width: 1,
21
+ height: 1,
21
22
  sampler: {
22
23
  minFilter: 'linear',
23
24
  magFilter: 'linear',
@@ -145,18 +145,7 @@ export default class RasterLayer<DataT = any, ExtraProps = {}> extends Composite
145
145
  offset,
146
146
  lineWidthScale, // Re-use widthScale prop to pass cell scale,
147
147
  highlightedObjectIndex,
148
- highlightColor,
149
-
150
- // RTT requires blending otherwise opacity < 1 blends with black
151
- // render target
152
- parameters: {
153
- blendColorSrcFactor: 'one',
154
- blendAlphaSrcFactor: 'one',
155
- blendColorDstFactor: 'zero',
156
- blendAlphaDstFactor: 'zero',
157
- blendColorOperation: 'add',
158
- blendAlphaOperation: 'add'
159
- }
148
+ highlightColor
160
149
  }
161
150
  );
162
151
  }