@deck.gl-community/geo-layers 9.2.0-beta.3

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 (90) hide show
  1. package/LICENSE +19 -0
  2. package/README.md +5 -0
  3. package/dist/global-grid-layer/global-grid-cluster-layer.d.ts +36 -0
  4. package/dist/global-grid-layer/global-grid-cluster-layer.d.ts.map +1 -0
  5. package/dist/global-grid-layer/global-grid-cluster-layer.js +55 -0
  6. package/dist/global-grid-layer/global-grid-cluster-layer.js.map +1 -0
  7. package/dist/global-grid-layer/global-grid-layer.d.ts +21 -0
  8. package/dist/global-grid-layer/global-grid-layer.d.ts.map +1 -0
  9. package/dist/global-grid-layer/global-grid-layer.js +33 -0
  10. package/dist/global-grid-layer/global-grid-layer.js.map +1 -0
  11. package/dist/global-grid-systems/grids/a5-grid.d.ts +18 -0
  12. package/dist/global-grid-systems/grids/a5-grid.d.ts.map +1 -0
  13. package/dist/global-grid-systems/grids/a5-grid.js +23 -0
  14. package/dist/global-grid-systems/grids/a5-grid.js.map +1 -0
  15. package/dist/global-grid-systems/grids/geohash-grid.d.ts +15 -0
  16. package/dist/global-grid-systems/grids/geohash-grid.d.ts.map +1 -0
  17. package/dist/global-grid-systems/grids/geohash-grid.js +92 -0
  18. package/dist/global-grid-systems/grids/geohash-grid.js.map +1 -0
  19. package/dist/global-grid-systems/grids/global-grid.d.ts +31 -0
  20. package/dist/global-grid-systems/grids/global-grid.d.ts.map +1 -0
  21. package/dist/global-grid-systems/grids/global-grid.js +5 -0
  22. package/dist/global-grid-systems/grids/global-grid.js.map +1 -0
  23. package/dist/global-grid-systems/grids/h3-grid.d.ts +16 -0
  24. package/dist/global-grid-systems/grids/h3-grid.d.ts.map +1 -0
  25. package/dist/global-grid-systems/grids/h3-grid.js +29 -0
  26. package/dist/global-grid-systems/grids/h3-grid.js.map +1 -0
  27. package/dist/global-grid-systems/grids/quadkey-grid.d.ts +41 -0
  28. package/dist/global-grid-systems/grids/quadkey-grid.d.ts.map +1 -0
  29. package/dist/global-grid-systems/grids/quadkey-grid.js +166 -0
  30. package/dist/global-grid-systems/grids/quadkey-grid.js.map +1 -0
  31. package/dist/global-grid-systems/grids/s2-grid.d.ts +16 -0
  32. package/dist/global-grid-systems/grids/s2-grid.d.ts.map +1 -0
  33. package/dist/global-grid-systems/grids/s2-grid.js +74 -0
  34. package/dist/global-grid-systems/grids/s2-grid.js.map +1 -0
  35. package/dist/global-grid-systems/h3-js-bigint/h3-js-bigint.d.ts +9 -0
  36. package/dist/global-grid-systems/h3-js-bigint/h3-js-bigint.d.ts.map +1 -0
  37. package/dist/global-grid-systems/h3-js-bigint/h3-js-bigint.js +62 -0
  38. package/dist/global-grid-systems/h3-js-bigint/h3-js-bigint.js.map +1 -0
  39. package/dist/global-grid-systems/s2-geometry/s2-geometry.d.ts +13 -0
  40. package/dist/global-grid-systems/s2-geometry/s2-geometry.d.ts.map +1 -0
  41. package/dist/global-grid-systems/s2-geometry/s2-geometry.js +139 -0
  42. package/dist/global-grid-systems/s2-geometry/s2-geometry.js.map +1 -0
  43. package/dist/global-grid-systems/s2-geometry/s2-to-boundary.d.ts +14 -0
  44. package/dist/global-grid-systems/s2-geometry/s2-to-boundary.d.ts.map +1 -0
  45. package/dist/global-grid-systems/s2-geometry/s2-to-boundary.js +60 -0
  46. package/dist/global-grid-systems/s2-geometry/s2-to-boundary.js.map +1 -0
  47. package/dist/global-grid-systems/s2-geometry/s2-token.d.ts +13 -0
  48. package/dist/global-grid-systems/s2-geometry/s2-token.d.ts.map +1 -0
  49. package/dist/global-grid-systems/s2-geometry/s2-token.js +61 -0
  50. package/dist/global-grid-systems/s2-geometry/s2-token.js.map +1 -0
  51. package/dist/global-grid-systems/utils/geometry-utils.d.ts +4 -0
  52. package/dist/global-grid-systems/utils/geometry-utils.d.ts.map +1 -0
  53. package/dist/global-grid-systems/utils/geometry-utils.js +26 -0
  54. package/dist/global-grid-systems/utils/geometry-utils.js.map +1 -0
  55. package/dist/global-grid-systems/utils/h3-utils.d.ts +5 -0
  56. package/dist/global-grid-systems/utils/h3-utils.d.ts.map +1 -0
  57. package/dist/global-grid-systems/utils/h3-utils.js +41 -0
  58. package/dist/global-grid-systems/utils/h3-utils.js.map +1 -0
  59. package/dist/global-grid-systems/utils/hex-utils.d.ts +8 -0
  60. package/dist/global-grid-systems/utils/hex-utils.d.ts.map +1 -0
  61. package/dist/global-grid-systems/utils/hex-utils.js +34 -0
  62. package/dist/global-grid-systems/utils/hex-utils.js.map +1 -0
  63. package/dist/index.cjs +640 -0
  64. package/dist/index.cjs.map +7 -0
  65. package/dist/index.d.ts +10 -0
  66. package/dist/index.d.ts.map +1 -0
  67. package/dist/index.js +11 -0
  68. package/dist/index.js.map +1 -0
  69. package/dist/tile-source-layer/tile-source-layer.d.ts +45 -0
  70. package/dist/tile-source-layer/tile-source-layer.d.ts.map +1 -0
  71. package/dist/tile-source-layer/tile-source-layer.js +110 -0
  72. package/dist/tile-source-layer/tile-source-layer.js.map +1 -0
  73. package/package.json +53 -0
  74. package/src/global-grid-layer/global-grid-cluster-layer.ts +93 -0
  75. package/src/global-grid-layer/global-grid-layer.ts +54 -0
  76. package/src/global-grid-systems/grids/a5-grid.ts +38 -0
  77. package/src/global-grid-systems/grids/geohash-grid.ts +105 -0
  78. package/src/global-grid-systems/grids/global-grid.ts +40 -0
  79. package/src/global-grid-systems/grids/h3-grid.ts +45 -0
  80. package/src/global-grid-systems/grids/quadkey-grid.ts +190 -0
  81. package/src/global-grid-systems/grids/s2-grid.ts +86 -0
  82. package/src/global-grid-systems/h3-js-bigint/h3-js-bigint.ts +85 -0
  83. package/src/global-grid-systems/s2-geometry/s2-geometry.ts +180 -0
  84. package/src/global-grid-systems/s2-geometry/s2-to-boundary.ts +76 -0
  85. package/src/global-grid-systems/s2-geometry/s2-token.ts +70 -0
  86. package/src/global-grid-systems/utils/geometry-utils.ts +28 -0
  87. package/src/global-grid-systems/utils/h3-utils.ts +52 -0
  88. package/src/global-grid-systems/utils/hex-utils.ts +37 -0
  89. package/src/index.ts +15 -0
  90. package/src/tile-source-layer/tile-source-layer.ts +156 -0
@@ -0,0 +1,180 @@
1
+ // math.gl
2
+ // SPDX-License-Identifier: MIT and ISC
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ // math.gl, MIT license
6
+ /*
7
+ Adapted from s2-geometry under ISC License (ISC)
8
+ Copyright (c) 2012-2016, Jon Atkins <github@jonatkins.com>
9
+ Copyright (c) 2016, AJ ONeal <aj@daplie.com>
10
+ Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
12
+ */
13
+
14
+ export type S2Cell = {
15
+ face: number;
16
+ ij: [number, number];
17
+ level: number;
18
+ };
19
+
20
+ export function getS2Cell(s2Index: bigint): S2Cell {
21
+ const key = toHilbertQuadkey(s2Index);
22
+ const s2cell = fromHilbertQuadKey(key);
23
+ return s2cell;
24
+ }
25
+
26
+ //
27
+ // Functional Style
28
+ //
29
+ const FACE_BITS = 3;
30
+ const MAX_LEVEL = 30;
31
+ const POS_BITS = 2 * MAX_LEVEL + 1; // 61 (60 bits of data, 1 bit lsb marker)
32
+ const RADIAN_TO_DEGREE = 180 / Math.PI;
33
+
34
+ /*
35
+ Original function taken from deck.gl doesn't support the case of (face <= 5)
36
+ It's fixed here.
37
+ */
38
+ export function fromHilbertQuadKey(hilbertQuadkey: string): S2Cell {
39
+ const parts = hilbertQuadkey.split('/');
40
+ const face = parseInt(parts[0], 10);
41
+ const position = parts[1];
42
+ /*
43
+ Fix for the case of level==0 that corresponds to (face <= 5)
44
+ const maxLevel = position.length;
45
+ let level;
46
+ */
47
+ const maxLevel = face > 5 ? position.length : 0;
48
+ let level = 0;
49
+
50
+ const point = [0, 0] as [number, number];
51
+
52
+ for (let i = maxLevel - 1; i >= 0; i--) {
53
+ level = maxLevel - i;
54
+ const bit = position[i];
55
+ let rx = 0;
56
+ let ry = 0;
57
+ if (bit === '1') {
58
+ ry = 1;
59
+ } else if (bit === '2') {
60
+ rx = 1;
61
+ ry = 1;
62
+ } else if (bit === '3') {
63
+ rx = 1;
64
+ }
65
+
66
+ const val = Math.pow(2, level - 1);
67
+ rotateAndFlipQuadrant(val, point, rx, ry);
68
+
69
+ point[0] += val * rx;
70
+ point[1] += val * ry;
71
+ }
72
+
73
+ if (face % 2 === 1) {
74
+ const t = point[0];
75
+ point[0] = point[1];
76
+ point[1] = t;
77
+ }
78
+
79
+ return {face, ij: point, level};
80
+ }
81
+
82
+ export function toHilbertQuadkey(id: bigint): string {
83
+ let bin = id.toString(2);
84
+
85
+ while (bin.length < FACE_BITS + POS_BITS) {
86
+ // eslint-disable-next-line prefer-template
87
+ bin = '0' + bin;
88
+ }
89
+
90
+ // MUST come AFTER binstr has been left-padded with '0's
91
+ const lsbIndex = bin.lastIndexOf('1');
92
+ // substr(start, len)
93
+ // substring(start, end) // includes start, does not include end
94
+ const faceB = bin.substring(0, 3);
95
+ // posB will always be a multiple of 2 (or it's invalid)
96
+ const posB = bin.substring(3, lsbIndex);
97
+ const levelN = posB.length / 2;
98
+
99
+ const faceS = BigInt(`0b${faceB}`).toString(10);
100
+
101
+ /*
102
+ Here is a fix for the case when posB is an empty string that causes an exception in Long.fromString
103
+
104
+ let posS = Long.fromString(posB, true, 2).toString(4);
105
+ */
106
+ let posS = '0';
107
+ if (levelN !== 0) {
108
+ // posB is not an empty string< because levelN!==0
109
+ posS = BigInt(`0b${posB}`).toString(4);
110
+
111
+ while (posS.length < levelN) {
112
+ // eslint-disable-next-line prefer-template
113
+ posS = '0' + posS;
114
+ }
115
+ }
116
+ // Note, posS will be "0" for the level==0
117
+ // TODO: Is it ok?
118
+
119
+ return `${faceS}/${posS}`;
120
+ }
121
+
122
+ export function IJToST(
123
+ ij: [number, number],
124
+ order: number,
125
+ offsets: [number, number]
126
+ ): [number, number] {
127
+ const maxSize = 1 << order;
128
+
129
+ return [(ij[0] + offsets[0]) / maxSize, (ij[1] + offsets[1]) / maxSize];
130
+ }
131
+
132
+ function singleSTtoUV(st: number): number {
133
+ if (st >= 0.5) {
134
+ return (1 / 3.0) * (4 * st * st - 1);
135
+ }
136
+ return (1 / 3.0) * (1 - 4 * (1 - st) * (1 - st));
137
+ }
138
+
139
+ export function STToUV(st: [number, number]): [number, number] {
140
+ return [singleSTtoUV(st[0]), singleSTtoUV(st[1])];
141
+ }
142
+
143
+ export function FaceUVToXYZ(face: number, [u, v]: [number, number]): [number, number, number] {
144
+ switch (face) {
145
+ case 0:
146
+ return [1, u, v];
147
+ case 1:
148
+ return [-u, 1, v];
149
+ case 2:
150
+ return [-u, -v, 1];
151
+ case 3:
152
+ return [-1, -v, -u];
153
+ case 4:
154
+ return [v, -1, -u];
155
+ case 5:
156
+ return [v, u, -1];
157
+ default:
158
+ throw new Error('Invalid face');
159
+ }
160
+ }
161
+
162
+ export function XYZToLngLat([x, y, z]: [number, number, number]): [number, number] {
163
+ const lat = Math.atan2(z, Math.sqrt(x * x + y * y));
164
+ const lng = Math.atan2(y, x);
165
+
166
+ return [lng * RADIAN_TO_DEGREE, lat * RADIAN_TO_DEGREE];
167
+ }
168
+
169
+ function rotateAndFlipQuadrant(n: number, point: [number, number], rx: number, ry: number): void {
170
+ if (ry === 0) {
171
+ if (rx === 1) {
172
+ point[0] = n - 1 - point[0];
173
+ point[1] = n - 1 - point[1];
174
+ }
175
+
176
+ const x = point[0];
177
+ point[0] = point[1];
178
+ point[1] = x;
179
+ }
180
+ }
@@ -0,0 +1,76 @@
1
+ // math.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {IJToST, STToUV, FaceUVToXYZ, XYZToLngLat, getS2Cell} from './s2-geometry';
6
+
7
+ const MAX_RESOLUTION = 100;
8
+
9
+ export function getS2GeoBounds(s2Index: bigint): Float64Array {
10
+ const s2Cell = getS2Cell(s2Index);
11
+ return getS2GeoBoundsFromCell(s2Cell);
12
+ }
13
+
14
+ /**
15
+ * The S2 cell edge is curved: http://s2geometry.io/
16
+ * This is more prominent at lower levels
17
+ * resolution is the number of segments to generate per edge.
18
+ * We exponentially reduce resolution as level increases so it doesn't affect perf
19
+ * when there are a large number of cells
20
+ */
21
+ // eslint-disable-next-line max-statements
22
+ export function getS2GeoBoundsFromCell({
23
+ face,
24
+ ij,
25
+ level
26
+ }: {
27
+ face: number;
28
+ ij: [number, number];
29
+ level: number;
30
+ }): Float64Array {
31
+ const offsets = [
32
+ [0, 0],
33
+ [0, 1],
34
+ [1, 1],
35
+ [1, 0],
36
+ [0, 0]
37
+ ];
38
+
39
+ const resolution = Math.max(1, Math.ceil(MAX_RESOLUTION * Math.pow(2, -level)));
40
+ const result = new Float64Array(4 * resolution * 2 + 2);
41
+ let ptIndex = 0;
42
+ let prevLng = 0;
43
+
44
+ for (let i = 0; i < 4; i++) {
45
+ const offset = offsets[i].slice(0) as [number, number];
46
+ const nextOffset = offsets[i + 1];
47
+ const stepI = (nextOffset[0] - offset[0]) / resolution;
48
+ const stepJ = (nextOffset[1] - offset[1]) / resolution;
49
+
50
+ for (let j = 0; j < resolution; j++) {
51
+ offset[0] += stepI;
52
+ offset[1] += stepJ;
53
+ // Cell can be represented by coordinates IJ, ST, UV, XYZ
54
+ // http://s2geometry.io/devguide/s2cell_hierarchy#coordinate-systems
55
+ const st = IJToST(ij, level, offset);
56
+ const uv = STToUV(st);
57
+ const xyz = FaceUVToXYZ(face, uv);
58
+ const lngLat = XYZToLngLat(xyz);
59
+
60
+ // Adjust longitude for Web Mercator projection
61
+ if (Math.abs(lngLat[1]) > 89.999) {
62
+ lngLat[0] = prevLng;
63
+ }
64
+ const deltaLng = lngLat[0] - prevLng;
65
+ lngLat[0] += deltaLng > 180 ? -360 : deltaLng < -180 ? 360 : 0;
66
+
67
+ result[ptIndex++] = lngLat[0];
68
+ result[ptIndex++] = lngLat[1];
69
+ prevLng = lngLat[0];
70
+ }
71
+ }
72
+ // close the loop
73
+ result[ptIndex++] = result[0];
74
+ result[ptIndex++] = result[1];
75
+ return result;
76
+ }
@@ -0,0 +1,70 @@
1
+ // math.gl
2
+ // SPDX-License-Identifier: MIT and Apache-2.0
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ // s2-geometry is a pure JavaScript port of Google/Niantic's S2 Geometry library
6
+ // which is perfect since it works in the browser.
7
+
8
+ // const MAXIMUM_TOKEN_LENGTH = 16;
9
+
10
+ // INDEX CALCULATIONS
11
+
12
+ /**
13
+ * Given an S2 token (String) this function convert the token to 64 bit id (Index)
14
+ * 'X' is the empty cell
15
+ * https://github.com/google/s2-geometry-library-java/blob/c04b68bf3197a9c34082327eeb3aec7ab7c85da1/src/com/google/common/geometry/S2CellId.java#L439
16
+ */
17
+ export function getS2IndexFromToken(token: string): bigint {
18
+ if (token === 'X') {
19
+ token = '';
20
+ }
21
+ // pad token with zeros to make the length 16
22
+ const paddedToken = token.padEnd(16, '0');
23
+ return BigInt(`0x${paddedToken}`);
24
+ }
25
+
26
+ /**
27
+ * Convert a 64 bit number to a string token
28
+ * 'X' is the empty cell
29
+ */
30
+ export function getS2TokenFromIndex(cellId: bigint): string {
31
+ if (cellId === 0n) {
32
+ return 'X';
33
+ }
34
+ let numZeroDigits = countTrailingZeros(cellId);
35
+
36
+ const remainder = numZeroDigits % 4;
37
+ numZeroDigits = (numZeroDigits - remainder) / 4;
38
+ const trailingZeroHexChars = numZeroDigits;
39
+ numZeroDigits *= 4;
40
+
41
+ const x = cellId >> BigInt(numZeroDigits);
42
+ const hexString = x.toString(16).replace(/0+$/, '');
43
+ const zeroString = Array(17 - trailingZeroHexChars - hexString.length).join('0');
44
+ return zeroString + hexString;
45
+ }
46
+
47
+ export function getS2ChildIndex(s2Index: bigint, index: number): bigint {
48
+ // Shift sentinel bit 2 positions to the right.
49
+ const newLsb = lsb(s2Index) >> 2n;
50
+ // Insert child index before the sentinel bit.
51
+ const childCellId: bigint = s2Index + BigInt(2 * index + 1 - 4) * newLsb;
52
+ return childCellId;
53
+ }
54
+
55
+ /**
56
+ * Return the lowest-numbered bit that is on for this cell id
57
+ * @private
58
+ */
59
+ function lsb(cellId: bigint): bigint {
60
+ return cellId & (cellId + 1n); // eslint-disable-line
61
+ }
62
+
63
+ function countTrailingZeros(n: bigint): number {
64
+ let count = 0;
65
+ while (n % 2n === 0n) {
66
+ n /= 2n;
67
+ count++;
68
+ }
69
+ return count;
70
+ }
@@ -0,0 +1,28 @@
1
+ // deck.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {type CoordPair} from '../h3-js-bigint/h3-js-bigint';
6
+
7
+ // normalize longitudes w.r.t center (refLng), when not provided first vertex
8
+ export function normalizeLongitudes(vertices: CoordPair[], refLng?: number): void {
9
+ refLng = refLng === undefined ? vertices[0][0] : refLng;
10
+ for (const pt of vertices) {
11
+ const deltaLng = pt[0] - refLng;
12
+ if (deltaLng > 180) {
13
+ pt[0] -= 360;
14
+ } else if (deltaLng < -180) {
15
+ pt[0] += 360;
16
+ }
17
+ }
18
+ }
19
+
20
+ export function flattenPolygon(vertices: number[][]): Float64Array {
21
+ const positions = new Float64Array(vertices.length * 2);
22
+ let i = 0;
23
+ for (const pt of vertices) {
24
+ positions[i++] = pt[0];
25
+ positions[i++] = pt[1];
26
+ }
27
+ return positions;
28
+ }
@@ -0,0 +1,52 @@
1
+ // deck.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {lerp} from '@math.gl/core';
6
+ import {
7
+ type CoordPair,
8
+ type H3IndexInput, // Either string or SplitLong
9
+ cellToBoundary,
10
+ cellToLatLng
11
+ } from '../h3-js-bigint/h3-js-bigint';
12
+ import {normalizeLongitudes} from './geometry-utils';
13
+
14
+ // UTILITIES - TODO can these be generalized using the decoder?
15
+
16
+ // scale polygon vertices w.r.t center (hexId)
17
+ export function scalePolygon(hexId: H3IndexInput, vertices: CoordPair[], factor: number): void {
18
+ const [lat, lng] = cellToLatLng(hexId);
19
+ const actualCount = vertices.length;
20
+
21
+ // normalize with respect to center
22
+ normalizeLongitudes(vertices, lng);
23
+
24
+ // `cellToBoundary` returns same array object for first and last vertex (closed polygon),
25
+ // if so skip scaling the last vertex
26
+ const vertexCount = vertices[0] === vertices[actualCount - 1] ? actualCount - 1 : actualCount;
27
+ for (let i = 0; i < vertexCount; i++) {
28
+ vertices[i][0] = lerp(lng, vertices[i][0], factor);
29
+ vertices[i][1] = lerp(lat, vertices[i][1], factor);
30
+ }
31
+ }
32
+
33
+ // gets hexagon centroid
34
+ export function getHexagonCentroid(getHexagon, object, objectInfo) {
35
+ const hexagonId = getHexagon(object, objectInfo);
36
+ const [lat, lng] = cellToLatLng(hexagonId);
37
+ return [lng, lat];
38
+ }
39
+
40
+ export function h3ToPolygon(hexId: H3IndexInput, coverage: number = 1): number[][] {
41
+ const vertices = cellToBoundary(hexId, true);
42
+
43
+ if (coverage !== 1) {
44
+ // scale and normalize vertices w.r.t to center
45
+ scalePolygon(hexId, vertices, coverage);
46
+ } else {
47
+ // normalize w.r.t to start vertex
48
+ normalizeLongitudes(vertices);
49
+ }
50
+
51
+ return vertices;
52
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Converts a hexadecimal string (with or without “0x” prefix) to a bigint.
3
+ * @param hex - The hex string representation (e.g., "0x1a2b", "FF", "00ff")
4
+ * @returns The corresponding bigint value.
5
+ * @throws {Error} If the input is not a valid hex string.
6
+ */
7
+ export function hexToBigInt(hex: string): bigint {
8
+ if (typeof hex !== 'string') {
9
+ throw new Error(`hexToBigInt: expected string, got ${typeof hex}`);
10
+ }
11
+
12
+ let s = hex.trim();
13
+ if (s.startsWith('0x') || s.startsWith('0X')) {
14
+ s = s.slice(2);
15
+ }
16
+
17
+ if (s === '') {
18
+ throw new Error(`hexToBigInt: empty hex string`);
19
+ }
20
+
21
+ // validate: only hex digits
22
+ if (!/^[0-9A-Fa-f]+$/.test(s)) {
23
+ throw new Error(`hexToBigInt: invalid hex string “${hex}”`);
24
+ }
25
+
26
+ // Optional: normalize even length by prepending a zero if odd
27
+ if (s.length % 2 === 1) {
28
+ s = `0${ s}`;
29
+ }
30
+
31
+ // Use BigInt conversion from string with 0x prefix
32
+ try {
33
+ return BigInt(`0x${ s}`);
34
+ } catch (e) {
35
+ throw new Error(`hexToBigInt: cannot convert hex string “${hex}” to bigint: ${(e as Error).message}`);
36
+ }
37
+ }
package/src/index.ts ADDED
@@ -0,0 +1,15 @@
1
+ // deck.gl-community
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ export type {TileSourceLayerProps} from './tile-source-layer/tile-source-layer';
6
+ export {TileSourceLayer} from './tile-source-layer/tile-source-layer';
7
+
8
+ export {GlobalGridLayer, type GlobalGridLayerProps} from './global-grid-layer/global-grid-layer';
9
+
10
+ export {type GlobalGrid} from './global-grid-systems/grids/global-grid';
11
+ export {A5Grid} from './global-grid-systems/grids/a5-grid';
12
+ export {H3Grid} from './global-grid-systems/grids/h3-grid';
13
+ export {S2Grid} from './global-grid-systems/grids/s2-grid';
14
+ export {GeohashGrid} from './global-grid-systems/grids/geohash-grid';
15
+ export {QuadkeyGrid} from './global-grid-systems/grids/quadkey-grid';
@@ -0,0 +1,156 @@
1
+ // deck.gl-community
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {CompositeLayer, Layer} from '@deck.gl/core';
6
+ import type {TileLayerProps} from '@deck.gl/geo-layers';
7
+ import {TileLayer} from '@deck.gl/geo-layers';
8
+ import {BitmapLayer, GeoJsonLayer, PathLayer} from '@deck.gl/layers';
9
+ import type {TileSource} from '@loaders.gl/loader-utils';
10
+
11
+ /* global window */
12
+ const devicePixelRatio = (typeof window !== 'undefined' && window.devicePixelRatio) || 1;
13
+
14
+ export type TileSourceLayerProps = TileLayerProps & {
15
+ tileSource: TileSource<any>;
16
+ showTileBorders?: boolean;
17
+ };
18
+
19
+ /**
20
+ * A Deck.gl layer that renders a tile source
21
+ * Autodiscovers type of content (vector tile, bitmap, ...)
22
+ * Can render debug borders around tiles
23
+ * TODO - Change debug border color based on zoom level
24
+ */
25
+ export class TileSourceLayer extends CompositeLayer<TileSourceLayerProps> {
26
+ static layerName = 'TileSourceLayer';
27
+ static defaultProps = {
28
+ ...TileLayer.defaultProps,
29
+ showTileBorders: true
30
+ };
31
+
32
+ state: {
33
+ tileSource: TileSource<any> | null;
34
+ } = undefined!;
35
+
36
+ initializeState() {
37
+ this.setState({
38
+ tileSource: null
39
+ });
40
+ }
41
+
42
+ updateState({props, changeFlags}) {
43
+ this.setState({
44
+ tileSource: props.tileSource
45
+ });
46
+ }
47
+
48
+ renderLayers() {
49
+ const {tileSource, showTileBorders, metadata, onTilesLoad} = this.props as any;
50
+ const minZoom = metadata?.minZoom || 0;
51
+ const maxZoom = metadata?.maxZoom || 30;
52
+
53
+ return [
54
+ new TileLayer({
55
+ // HACK: Trigger new layer via id prop to force clear tile cache
56
+ id: String(tileSource.url),
57
+ getTileData: tileSource.getTileData,
58
+ // Assume the pmtiles file support HTTP/2, so we aren't limited by the browser to a certain number per domain.
59
+ maxRequests: 20,
60
+
61
+ pickable: true,
62
+ onViewportLoad: onTilesLoad,
63
+ autoHighlight: showTileBorders,
64
+ highlightColor: [60, 60, 60, 40],
65
+ minZoom,
66
+ maxZoom,
67
+ tileSize: 256,
68
+ // TOOD - why is this needed?
69
+ zoomOffset: devicePixelRatio === 1 ? -1 : 0,
70
+ renderSubLayers: renderSubLayers as any,
71
+
72
+ // Custom prop
73
+ tileSource,
74
+ showTileBorders
75
+ })
76
+ ];
77
+ }
78
+ }
79
+
80
+ function renderSubLayers(
81
+ props: TileSourceLayerProps & {tile: {index; bbox: {west; south; east; north}}}
82
+ ) {
83
+ const {
84
+ tileSource,
85
+ showTileBorders,
86
+ minZoom,
87
+ maxZoom,
88
+ tile: {
89
+ index: {z: zoom},
90
+ bbox: {west, south, east, north}
91
+ }
92
+ } = props as any;
93
+
94
+ const layers: Layer[] = [];
95
+
96
+ const borderColor = zoom <= minZoom || zoom >= maxZoom ? [255, 0, 0, 255] : [0, 0, 255, 255];
97
+
98
+ switch (tileSource.mimeType) {
99
+ case 'application/vnd.mapbox-vector-tile':
100
+ layers.push(
101
+ new GeoJsonLayer({
102
+ id: `${props.id}-geojson`,
103
+ data: props.data as any,
104
+ pickable: true,
105
+ getFillColor: [0, 190, 80, 255],
106
+ lineWidthScale: 500,
107
+ lineWidthMinPixels: 0.5
108
+ })
109
+ );
110
+ break;
111
+
112
+ case 'image/png':
113
+ case 'image/jpeg':
114
+ case 'image/webp':
115
+ case 'image/avif':
116
+ layers.push(
117
+ new BitmapLayer(
118
+ props as any,
119
+ {
120
+ data: null,
121
+ image: props.data,
122
+ bounds: [west, south, east, north],
123
+ pickable: true
124
+ } as any
125
+ )
126
+ );
127
+ break;
128
+
129
+ default:
130
+ // eslint-disable-next-line no-console
131
+ console.error('Unknown tile mimeType', tileSource?.mimeType);
132
+ }
133
+
134
+ // Debug tile borders
135
+ if (showTileBorders) {
136
+ layers.push(
137
+ new PathLayer({
138
+ id: `${props.id}-border`,
139
+ data: [
140
+ [
141
+ [west, north],
142
+ [west, south],
143
+ [east, south],
144
+ [east, north],
145
+ [west, north]
146
+ ]
147
+ ],
148
+ getPath: (d) => d,
149
+ getColor: borderColor as any,
150
+ widthMinPixels: 4
151
+ })
152
+ );
153
+ }
154
+
155
+ return layers;
156
+ }