├── 2023-07-lerc-dem-color-ramp.webp ├── README.md ├── index.deck.html ├── index.html ├── package-lock.json ├── package.json └── src ├── cogs.ts ├── delatin.ts ├── index.deck.gl.ts ├── index.ts ├── quadkey.ts └── ramp.ts /2023-07-lerc-dem-color-ramp.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/blacha/lerc-cog-maplibre/9da9c859009c1bfb7d4828ebf5bcebea6bec543e/2023-07-lerc-dem-color-ramp.webp -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LERC COGs as Maplibre DEM source 2 | 3 | ![Example render](./2023-07-lerc-dem-color-ramp.webp) 4 | 5 | Grab some elevation data eg https://data.linz.govt.nz/layer/107436-taranaki-lidar-1m-dem-2021/ 6 | 7 | Make VRT 8 | 9 | ```bash 10 | gdalbuildvrt ../BJ29.vrt *.tif 11 | ``` 12 | 13 | Create a 3857 LERC COG 14 | 15 | ```bash 16 | gdal_translate -of COG \ 17 | -co TILING_SCHEME=GoogleMapsCompatible \ 18 | -co NUM_THREADS=ALL_CPUS \ 19 | -co BIGTIFF=NO \ 20 | -co ADD_ALPHA=YES \ 21 | -co BLOCKSIZE=256 \ 22 | -co SPARSE_OK=YES \ 23 | -co compress=lerc -co max_z_error=0.01 \ # 1cm of error 24 | BJ29.vrt BJ29.lerc.cog.tiff 25 | ``` 26 | 27 | bundle everything 28 | ```bash 29 | npm i 30 | npm run bundle 31 | ``` 32 | 33 | Start a local webserver 34 | ```bash 35 | serve . 36 | open http://localhost:3000 37 | ``` 38 | -------------------------------------------------------------------------------- /index.deck.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DeckGL example 6 | 7 | 24 | 25 | 26 |
27 | 28 |
29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | LERC Terrain 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | 18 | 19 |
20 | 21 | 22 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dem-map", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "dem-map", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "@basemaps/geo": "^6.40.0", 13 | "@basemaps/tiler": "^6.40.0", 14 | "@chunkd/source-url": "^6.0.0", 15 | "@cogeotiff/core": "^7.2.1", 16 | "@deck.gl/core": "^8.9.21", 17 | "@deck.gl/geo-layers": "^8.9.21", 18 | "esbuild": "^0.18.11", 19 | "lerc": "^4.0.1", 20 | "maplibre-gl": "^3.2.0" 21 | } 22 | }, 23 | "node_modules/@babel/runtime": { 24 | "version": "7.22.6", 25 | "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.6.tgz", 26 | "integrity": "sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==", 27 | "dependencies": { 28 | "regenerator-runtime": "^0.13.11" 29 | }, 30 | "engines": { 31 | "node": ">=6.9.0" 32 | } 33 | }, 34 | "node_modules/@basemaps/geo": { 35 | "version": "6.40.0", 36 | "resolved": "https://registry.npmjs.org/@basemaps/geo/-/geo-6.40.0.tgz", 37 | "integrity": "sha512-bhd8Vb4GXyV9XWC1gXg7Hpv/hkvu17wPHfIi7jQiCk20JCvDOql4X0HqbDJDow26AJd7VeWXiLQ/310jXHOREg==", 38 | "dependencies": { 39 | "@linzjs/tile-matrix-set": "^0.0.1" 40 | }, 41 | "engines": { 42 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 43 | } 44 | }, 45 | "node_modules/@basemaps/tiler": { 46 | "version": "6.40.0", 47 | "resolved": "https://registry.npmjs.org/@basemaps/tiler/-/tiler-6.40.0.tgz", 48 | "integrity": "sha512-zRm6bS9DFM2PbRWwwY0uO/I+cTycI0fUX/T3NwqPd/bTDuRn3TvGYG5oRlqMlttxOtVB4GOjyMarXDTZigJe0Q==", 49 | "dependencies": { 50 | "@basemaps/geo": "^6.40.0", 51 | "@cogeotiff/core": "^7.2.0", 52 | "@linzjs/metrics": "^6.32.1" 53 | }, 54 | "engines": { 55 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 56 | } 57 | }, 58 | "node_modules/@chunkd/core": { 59 | "version": "6.0.0", 60 | "resolved": "https://registry.npmjs.org/@chunkd/core/-/core-6.0.0.tgz", 61 | "integrity": "sha512-3s11Z4c/4GI6a6U7RWeh5R3Wf/kxcQtSCOy1RK/D3ZPWCDoHkiNkTSCtXUodZWkkHmIhvBl5qdOJEpVDt2B+qQ==", 62 | "engines": { 63 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 64 | } 65 | }, 66 | "node_modules/@chunkd/source-url": { 67 | "version": "6.0.0", 68 | "resolved": "https://registry.npmjs.org/@chunkd/source-url/-/source-url-6.0.0.tgz", 69 | "integrity": "sha512-BXKweOJu+bNmDcgqfDUqmMKVln+TrmSFZSSJeLpBVGPg4x8CqemESgUaFVORyER9o4Fhq8MDcLsfdApqDSXsIg==", 70 | "dependencies": { 71 | "@chunkd/core": "^6.0.0", 72 | "node-fetch": "^2.6.0" 73 | }, 74 | "engines": { 75 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 76 | } 77 | }, 78 | "node_modules/@cogeotiff/core": { 79 | "version": "7.2.1", 80 | "resolved": "https://registry.npmjs.org/@cogeotiff/core/-/core-7.2.1.tgz", 81 | "integrity": "sha512-jA2AvDUFriRNcttMsz8dZxvDw25iNC/iRJWu4ayMIDcY3gJ9jZ1u0AUU9vOSk/o3eIBrMq2aIF17sRZjSIMphw==", 82 | "dependencies": { 83 | "@chunkd/core": "^10.0.0", 84 | "ieee754": "^1.1.13" 85 | }, 86 | "engines": { 87 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 88 | } 89 | }, 90 | "node_modules/@cogeotiff/core/node_modules/@chunkd/core": { 91 | "version": "10.3.0", 92 | "resolved": "https://registry.npmjs.org/@chunkd/core/-/core-10.3.0.tgz", 93 | "integrity": "sha512-a284uWnisLtDbMBMRMPHWsHConhcozOUmRKhw27FXbleuvoqYAHlwE7nfSFFOg6ho1wWhbEIyVfh/nTz8kLkOA==", 94 | "engines": { 95 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 96 | } 97 | }, 98 | "node_modules/@deck.gl/core": { 99 | "version": "8.9.21", 100 | "resolved": "https://registry.npmjs.org/@deck.gl/core/-/core-8.9.21.tgz", 101 | "integrity": "sha512-kyPOEkl90T5agiNhIPCool03/4MMQXKoNqSurdXtJS7+xU9FVf7/biTrLxVxWCfF8kqRgxX6sJ4m2PKUwRjV0A==", 102 | "dependencies": { 103 | "@babel/runtime": "^7.0.0", 104 | "@loaders.gl/core": "^3.4.2", 105 | "@loaders.gl/images": "^3.4.2", 106 | "@luma.gl/constants": "^8.5.20", 107 | "@luma.gl/core": "^8.5.20", 108 | "@luma.gl/webgl": "^8.5.20", 109 | "@math.gl/core": "^3.6.2", 110 | "@math.gl/sun": "^3.6.2", 111 | "@math.gl/web-mercator": "^3.6.2", 112 | "@probe.gl/env": "^3.5.0", 113 | "@probe.gl/log": "^3.5.0", 114 | "@probe.gl/stats": "^3.5.0", 115 | "gl-matrix": "^3.0.0", 116 | "math.gl": "^3.6.2", 117 | "mjolnir.js": "^2.7.0" 118 | } 119 | }, 120 | "node_modules/@deck.gl/extensions": { 121 | "version": "8.9.21", 122 | "resolved": "https://registry.npmjs.org/@deck.gl/extensions/-/extensions-8.9.21.tgz", 123 | "integrity": "sha512-GIVeRG8K7uJfiKktfsFlgMv5kwKWPEgFkYsxxr/NY6UnqNRgAn9B+aH6YgJ4Hu22xwjUTOtzrX6BrSnsQI3kOg==", 124 | "peer": true, 125 | "dependencies": { 126 | "@babel/runtime": "^7.0.0", 127 | "@luma.gl/shadertools": "^8.5.20" 128 | }, 129 | "peerDependencies": { 130 | "@deck.gl/core": "^8.0.0", 131 | "@luma.gl/constants": "^8.0.0", 132 | "@luma.gl/core": "^8.0.0", 133 | "@math.gl/core": "^3.6.2", 134 | "@math.gl/web-mercator": "^3.6.2", 135 | "gl-matrix": "^3.0.0" 136 | } 137 | }, 138 | "node_modules/@deck.gl/geo-layers": { 139 | "version": "8.9.21", 140 | "resolved": "https://registry.npmjs.org/@deck.gl/geo-layers/-/geo-layers-8.9.21.tgz", 141 | "integrity": "sha512-JS01acqO6weF9MUAdT/GVGABMHbkWKB/ZRinJ0HBqOyiZNpJ9k8SpwCiBP8jDwYfQ9Ziz8SGFNU/DmtNI9Vgxg==", 142 | "dependencies": { 143 | "@babel/runtime": "^7.0.0", 144 | "@loaders.gl/3d-tiles": "^3.4.2", 145 | "@loaders.gl/gis": "^3.4.2", 146 | "@loaders.gl/loader-utils": "^3.4.2", 147 | "@loaders.gl/mvt": "^3.4.2", 148 | "@loaders.gl/schema": "^3.4.2", 149 | "@loaders.gl/terrain": "^3.4.2", 150 | "@loaders.gl/tiles": "^3.4.2", 151 | "@loaders.gl/wms": "^3.4.2", 152 | "@luma.gl/constants": "^8.5.20", 153 | "@luma.gl/experimental": "^8.5.20", 154 | "@math.gl/core": "^3.6.2", 155 | "@math.gl/culling": "^3.6.2", 156 | "@math.gl/web-mercator": "^3.6.2", 157 | "@types/geojson": "^7946.0.8", 158 | "h3-js": "^3.7.0", 159 | "long": "^3.2.0" 160 | }, 161 | "peerDependencies": { 162 | "@deck.gl/core": "^8.0.0", 163 | "@deck.gl/extensions": "^8.0.0", 164 | "@deck.gl/layers": "^8.0.0", 165 | "@deck.gl/mesh-layers": "^8.0.0", 166 | "@loaders.gl/core": "^3.4.2", 167 | "@luma.gl/core": "^8.0.0" 168 | } 169 | }, 170 | "node_modules/@deck.gl/layers": { 171 | "version": "8.9.21", 172 | "resolved": "https://registry.npmjs.org/@deck.gl/layers/-/layers-8.9.21.tgz", 173 | "integrity": "sha512-tNxbBhFcc81mBaSK+zNxvhlmZmQNuYmUJMWymWMq5vz5MLTE6hHNjLY5n181ZSYspHDA/7tsjXXZ5c/+MGru2g==", 174 | "peer": true, 175 | "dependencies": { 176 | "@babel/runtime": "^7.0.0", 177 | "@loaders.gl/images": "^3.4.2", 178 | "@loaders.gl/schema": "^3.4.2", 179 | "@luma.gl/constants": "^8.5.20", 180 | "@mapbox/tiny-sdf": "^2.0.5", 181 | "@math.gl/core": "^3.6.2", 182 | "@math.gl/polygon": "^3.6.2", 183 | "@math.gl/web-mercator": "^3.6.2", 184 | "earcut": "^2.2.4" 185 | }, 186 | "peerDependencies": { 187 | "@deck.gl/core": "^8.0.0", 188 | "@loaders.gl/core": "^3.4.2", 189 | "@luma.gl/core": "^8.0.0" 190 | } 191 | }, 192 | "node_modules/@deck.gl/mesh-layers": { 193 | "version": "8.9.21", 194 | "resolved": "https://registry.npmjs.org/@deck.gl/mesh-layers/-/mesh-layers-8.9.21.tgz", 195 | "integrity": "sha512-alTRtuZADvz18txumJeE/cTJQ6I1DqYDHGGFHA/FlKA3kYcy91Te4evHSok/+k8xlNyzf26cjgs9EoHAbUDpuQ==", 196 | "peer": true, 197 | "dependencies": { 198 | "@babel/runtime": "^7.0.0", 199 | "@loaders.gl/gltf": "^3.4.2", 200 | "@luma.gl/constants": "^8.5.20", 201 | "@luma.gl/experimental": "^8.5.20", 202 | "@luma.gl/shadertools": "^8.5.20" 203 | }, 204 | "peerDependencies": { 205 | "@deck.gl/core": "^8.0.0", 206 | "@luma.gl/core": "^8.0.0" 207 | } 208 | }, 209 | "node_modules/@esbuild/android-arm": { 210 | "version": "0.18.11", 211 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.11.tgz", 212 | "integrity": "sha512-q4qlUf5ucwbUJZXF5tEQ8LF7y0Nk4P58hOsGk3ucY0oCwgQqAnqXVbUuahCddVHfrxmpyewRpiTHwVHIETYu7Q==", 213 | "cpu": [ 214 | "arm" 215 | ], 216 | "optional": true, 217 | "os": [ 218 | "android" 219 | ], 220 | "engines": { 221 | "node": ">=12" 222 | } 223 | }, 224 | "node_modules/@esbuild/android-arm64": { 225 | "version": "0.18.11", 226 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.11.tgz", 227 | "integrity": "sha512-snieiq75Z1z5LJX9cduSAjUr7vEI1OdlzFPMw0HH5YI7qQHDd3qs+WZoMrWYDsfRJSq36lIA6mfZBkvL46KoIw==", 228 | "cpu": [ 229 | "arm64" 230 | ], 231 | "optional": true, 232 | "os": [ 233 | "android" 234 | ], 235 | "engines": { 236 | "node": ">=12" 237 | } 238 | }, 239 | "node_modules/@esbuild/android-x64": { 240 | "version": "0.18.11", 241 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.11.tgz", 242 | "integrity": "sha512-iPuoxQEV34+hTF6FT7om+Qwziv1U519lEOvekXO9zaMMlT9+XneAhKL32DW3H7okrCOBQ44BMihE8dclbZtTuw==", 243 | "cpu": [ 244 | "x64" 245 | ], 246 | "optional": true, 247 | "os": [ 248 | "android" 249 | ], 250 | "engines": { 251 | "node": ">=12" 252 | } 253 | }, 254 | "node_modules/@esbuild/darwin-arm64": { 255 | "version": "0.18.11", 256 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.11.tgz", 257 | "integrity": "sha512-Gm0QkI3k402OpfMKyQEEMG0RuW2LQsSmI6OeO4El2ojJMoF5NLYb3qMIjvbG/lbMeLOGiW6ooU8xqc+S0fgz2w==", 258 | "cpu": [ 259 | "arm64" 260 | ], 261 | "optional": true, 262 | "os": [ 263 | "darwin" 264 | ], 265 | "engines": { 266 | "node": ">=12" 267 | } 268 | }, 269 | "node_modules/@esbuild/darwin-x64": { 270 | "version": "0.18.11", 271 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.11.tgz", 272 | "integrity": "sha512-N15Vzy0YNHu6cfyDOjiyfJlRJCB/ngKOAvoBf1qybG3eOq0SL2Lutzz9N7DYUbb7Q23XtHPn6lMDF6uWbGv9Fw==", 273 | "cpu": [ 274 | "x64" 275 | ], 276 | "optional": true, 277 | "os": [ 278 | "darwin" 279 | ], 280 | "engines": { 281 | "node": ">=12" 282 | } 283 | }, 284 | "node_modules/@esbuild/freebsd-arm64": { 285 | "version": "0.18.11", 286 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.11.tgz", 287 | "integrity": "sha512-atEyuq6a3omEY5qAh5jIORWk8MzFnCpSTUruBgeyN9jZq1K/QI9uke0ATi3MHu4L8c59CnIi4+1jDKMuqmR71A==", 288 | "cpu": [ 289 | "arm64" 290 | ], 291 | "optional": true, 292 | "os": [ 293 | "freebsd" 294 | ], 295 | "engines": { 296 | "node": ">=12" 297 | } 298 | }, 299 | "node_modules/@esbuild/freebsd-x64": { 300 | "version": "0.18.11", 301 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.11.tgz", 302 | "integrity": "sha512-XtuPrEfBj/YYYnAAB7KcorzzpGTvOr/dTtXPGesRfmflqhA4LMF0Gh/n5+a9JBzPuJ+CGk17CA++Hmr1F/gI0Q==", 303 | "cpu": [ 304 | "x64" 305 | ], 306 | "optional": true, 307 | "os": [ 308 | "freebsd" 309 | ], 310 | "engines": { 311 | "node": ">=12" 312 | } 313 | }, 314 | "node_modules/@esbuild/linux-arm": { 315 | "version": "0.18.11", 316 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.11.tgz", 317 | "integrity": "sha512-Idipz+Taso/toi2ETugShXjQ3S59b6m62KmLHkJlSq/cBejixmIydqrtM2XTvNCywFl3VC7SreSf6NV0i6sRyg==", 318 | "cpu": [ 319 | "arm" 320 | ], 321 | "optional": true, 322 | "os": [ 323 | "linux" 324 | ], 325 | "engines": { 326 | "node": ">=12" 327 | } 328 | }, 329 | "node_modules/@esbuild/linux-arm64": { 330 | "version": "0.18.11", 331 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.11.tgz", 332 | "integrity": "sha512-c6Vh2WS9VFKxKZ2TvJdA7gdy0n6eSy+yunBvv4aqNCEhSWVor1TU43wNRp2YLO9Vng2G+W94aRz+ILDSwAiYog==", 333 | "cpu": [ 334 | "arm64" 335 | ], 336 | "optional": true, 337 | "os": [ 338 | "linux" 339 | ], 340 | "engines": { 341 | "node": ">=12" 342 | } 343 | }, 344 | "node_modules/@esbuild/linux-ia32": { 345 | "version": "0.18.11", 346 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.11.tgz", 347 | "integrity": "sha512-S3hkIF6KUqRh9n1Q0dSyYcWmcVa9Cg+mSoZEfFuzoYXXsk6196qndrM+ZiHNwpZKi3XOXpShZZ+9dfN5ykqjjw==", 348 | "cpu": [ 349 | "ia32" 350 | ], 351 | "optional": true, 352 | "os": [ 353 | "linux" 354 | ], 355 | "engines": { 356 | "node": ">=12" 357 | } 358 | }, 359 | "node_modules/@esbuild/linux-loong64": { 360 | "version": "0.18.11", 361 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.11.tgz", 362 | "integrity": "sha512-MRESANOoObQINBA+RMZW+Z0TJWpibtE7cPFnahzyQHDCA9X9LOmGh68MVimZlM9J8n5Ia8lU773te6O3ILW8kw==", 363 | "cpu": [ 364 | "loong64" 365 | ], 366 | "optional": true, 367 | "os": [ 368 | "linux" 369 | ], 370 | "engines": { 371 | "node": ">=12" 372 | } 373 | }, 374 | "node_modules/@esbuild/linux-mips64el": { 375 | "version": "0.18.11", 376 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.11.tgz", 377 | "integrity": "sha512-qVyPIZrXNMOLYegtD1u8EBccCrBVshxMrn5MkuFc3mEVsw7CCQHaqZ4jm9hbn4gWY95XFnb7i4SsT3eflxZsUg==", 378 | "cpu": [ 379 | "mips64el" 380 | ], 381 | "optional": true, 382 | "os": [ 383 | "linux" 384 | ], 385 | "engines": { 386 | "node": ">=12" 387 | } 388 | }, 389 | "node_modules/@esbuild/linux-ppc64": { 390 | "version": "0.18.11", 391 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.11.tgz", 392 | "integrity": "sha512-T3yd8vJXfPirZaUOoA9D2ZjxZX4Gr3QuC3GztBJA6PklLotc/7sXTOuuRkhE9W/5JvJP/K9b99ayPNAD+R+4qQ==", 393 | "cpu": [ 394 | "ppc64" 395 | ], 396 | "optional": true, 397 | "os": [ 398 | "linux" 399 | ], 400 | "engines": { 401 | "node": ">=12" 402 | } 403 | }, 404 | "node_modules/@esbuild/linux-riscv64": { 405 | "version": "0.18.11", 406 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.11.tgz", 407 | "integrity": "sha512-evUoRPWiwuFk++snjH9e2cAjF5VVSTj+Dnf+rkO/Q20tRqv+644279TZlPK8nUGunjPAtQRCj1jQkDAvL6rm2w==", 408 | "cpu": [ 409 | "riscv64" 410 | ], 411 | "optional": true, 412 | "os": [ 413 | "linux" 414 | ], 415 | "engines": { 416 | "node": ">=12" 417 | } 418 | }, 419 | "node_modules/@esbuild/linux-s390x": { 420 | "version": "0.18.11", 421 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.11.tgz", 422 | "integrity": "sha512-/SlRJ15XR6i93gRWquRxYCfhTeC5PdqEapKoLbX63PLCmAkXZHY2uQm2l9bN0oPHBsOw2IswRZctMYS0MijFcg==", 423 | "cpu": [ 424 | "s390x" 425 | ], 426 | "optional": true, 427 | "os": [ 428 | "linux" 429 | ], 430 | "engines": { 431 | "node": ">=12" 432 | } 433 | }, 434 | "node_modules/@esbuild/linux-x64": { 435 | "version": "0.18.11", 436 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.11.tgz", 437 | "integrity": "sha512-xcncej+wF16WEmIwPtCHi0qmx1FweBqgsRtEL1mSHLFR6/mb3GEZfLQnx+pUDfRDEM4DQF8dpXIW7eDOZl1IbA==", 438 | "cpu": [ 439 | "x64" 440 | ], 441 | "optional": true, 442 | "os": [ 443 | "linux" 444 | ], 445 | "engines": { 446 | "node": ">=12" 447 | } 448 | }, 449 | "node_modules/@esbuild/netbsd-x64": { 450 | "version": "0.18.11", 451 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.11.tgz", 452 | "integrity": "sha512-aSjMHj/F7BuS1CptSXNg6S3M4F3bLp5wfFPIJM+Km2NfIVfFKhdmfHF9frhiCLIGVzDziggqWll0B+9AUbud/Q==", 453 | "cpu": [ 454 | "x64" 455 | ], 456 | "optional": true, 457 | "os": [ 458 | "netbsd" 459 | ], 460 | "engines": { 461 | "node": ">=12" 462 | } 463 | }, 464 | "node_modules/@esbuild/openbsd-x64": { 465 | "version": "0.18.11", 466 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.11.tgz", 467 | "integrity": "sha512-tNBq+6XIBZtht0xJGv7IBB5XaSyvYPCm1PxJ33zLQONdZoLVM0bgGqUrXnJyiEguD9LU4AHiu+GCXy/Hm9LsdQ==", 468 | "cpu": [ 469 | "x64" 470 | ], 471 | "optional": true, 472 | "os": [ 473 | "openbsd" 474 | ], 475 | "engines": { 476 | "node": ">=12" 477 | } 478 | }, 479 | "node_modules/@esbuild/sunos-x64": { 480 | "version": "0.18.11", 481 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.11.tgz", 482 | "integrity": "sha512-kxfbDOrH4dHuAAOhr7D7EqaYf+W45LsAOOhAet99EyuxxQmjbk8M9N4ezHcEiCYPaiW8Dj3K26Z2V17Gt6p3ng==", 483 | "cpu": [ 484 | "x64" 485 | ], 486 | "optional": true, 487 | "os": [ 488 | "sunos" 489 | ], 490 | "engines": { 491 | "node": ">=12" 492 | } 493 | }, 494 | "node_modules/@esbuild/win32-arm64": { 495 | "version": "0.18.11", 496 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.11.tgz", 497 | "integrity": "sha512-Sh0dDRyk1Xi348idbal7lZyfSkjhJsdFeuC13zqdipsvMetlGiFQNdO+Yfp6f6B4FbyQm7qsk16yaZk25LChzg==", 498 | "cpu": [ 499 | "arm64" 500 | ], 501 | "optional": true, 502 | "os": [ 503 | "win32" 504 | ], 505 | "engines": { 506 | "node": ">=12" 507 | } 508 | }, 509 | "node_modules/@esbuild/win32-ia32": { 510 | "version": "0.18.11", 511 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.11.tgz", 512 | "integrity": "sha512-o9JUIKF1j0rqJTFbIoF4bXj6rvrTZYOrfRcGyL0Vm5uJ/j5CkBD/51tpdxe9lXEDouhRgdr/BYzUrDOvrWwJpg==", 513 | "cpu": [ 514 | "ia32" 515 | ], 516 | "optional": true, 517 | "os": [ 518 | "win32" 519 | ], 520 | "engines": { 521 | "node": ">=12" 522 | } 523 | }, 524 | "node_modules/@esbuild/win32-x64": { 525 | "version": "0.18.11", 526 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.11.tgz", 527 | "integrity": "sha512-rQI4cjLHd2hGsM1LqgDI7oOCYbQ6IBOVsX9ejuRMSze0GqXUG2ekwiKkiBU1pRGSeCqFFHxTrcEydB2Hyoz9CA==", 528 | "cpu": [ 529 | "x64" 530 | ], 531 | "optional": true, 532 | "os": [ 533 | "win32" 534 | ], 535 | "engines": { 536 | "node": ">=12" 537 | } 538 | }, 539 | "node_modules/@linzjs/metrics": { 540 | "version": "6.32.1", 541 | "resolved": "https://registry.npmjs.org/@linzjs/metrics/-/metrics-6.32.1.tgz", 542 | "integrity": "sha512-QC2qYaYJkY2lnjHv6DGW3dbKkGO/ksyXMswhI6Mi27qcQxOi+gC8/Pac51op8/E4d/hmHyULCdCsCHKC2uTiLw==", 543 | "engines": { 544 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0" 545 | } 546 | }, 547 | "node_modules/@linzjs/tile-matrix-set": { 548 | "version": "0.0.1", 549 | "resolved": "https://registry.npmjs.org/@linzjs/tile-matrix-set/-/tile-matrix-set-0.0.1.tgz", 550 | "integrity": "sha512-qGyk/PUw6JWdYzHh4RHi3NUDdBCVJLQuT3HJbDwWZQF9bsqZcBSv8Irtd7Gu3U8WdyTNtazxh2eUxKRG7IzqYQ==" 551 | }, 552 | "node_modules/@loaders.gl/3d-tiles": { 553 | "version": "3.4.6", 554 | "resolved": "https://registry.npmjs.org/@loaders.gl/3d-tiles/-/3d-tiles-3.4.6.tgz", 555 | "integrity": "sha512-oM+wOg/HeYl8249Eq3fLT6L2ZU1wFXdXcyUsenaUubxuCKbWk/mwFyqHq3NINcy7K56TUlEXwxpaiRiIhZa9WA==", 556 | "dependencies": { 557 | "@loaders.gl/draco": "3.4.6", 558 | "@loaders.gl/gltf": "3.4.6", 559 | "@loaders.gl/loader-utils": "3.4.6", 560 | "@loaders.gl/math": "3.4.6", 561 | "@loaders.gl/tiles": "3.4.6", 562 | "@math.gl/core": "^3.5.1", 563 | "@math.gl/geospatial": "^3.5.1", 564 | "long": "^5.2.1" 565 | }, 566 | "peerDependencies": { 567 | "@loaders.gl/core": "^3.4.0" 568 | } 569 | }, 570 | "node_modules/@loaders.gl/3d-tiles/node_modules/long": { 571 | "version": "5.2.3", 572 | "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", 573 | "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" 574 | }, 575 | "node_modules/@loaders.gl/core": { 576 | "version": "3.4.6", 577 | "resolved": "https://registry.npmjs.org/@loaders.gl/core/-/core-3.4.6.tgz", 578 | "integrity": "sha512-9nang7w+McOg3ZippyFNz0+FuJu4bSkQkwpnIjUEr61JUiwpmRy5IakZP/LnmhZuzCy5+lDFj921md/l8Tduaw==", 579 | "dependencies": { 580 | "@babel/runtime": "^7.3.1", 581 | "@loaders.gl/loader-utils": "3.4.6", 582 | "@loaders.gl/worker-utils": "3.4.6", 583 | "@probe.gl/log": "^4.0.1" 584 | } 585 | }, 586 | "node_modules/@loaders.gl/core/node_modules/@probe.gl/env": { 587 | "version": "4.0.4", 588 | "resolved": "https://registry.npmjs.org/@probe.gl/env/-/env-4.0.4.tgz", 589 | "integrity": "sha512-sYNGqesDfWD6dFP5oNZtTeFA4Z6ak5T4a8BNPdNhoqy7PK9w70JHrb6mv+RKWqKXq33KiwCDWL7fYxx2HuEH2w==", 590 | "dependencies": { 591 | "@babel/runtime": "^7.0.0" 592 | } 593 | }, 594 | "node_modules/@loaders.gl/core/node_modules/@probe.gl/log": { 595 | "version": "4.0.4", 596 | "resolved": "https://registry.npmjs.org/@probe.gl/log/-/log-4.0.4.tgz", 597 | "integrity": "sha512-WpmXl6njlBMwrm8HBh/b4kSp/xnY1VVmeT4PWUKF+RkVbFuKQbsU11dA1IxoMd7gSY+5DGIwxGfAv1H5OMzA4A==", 598 | "dependencies": { 599 | "@babel/runtime": "^7.0.0", 600 | "@probe.gl/env": "4.0.4" 601 | } 602 | }, 603 | "node_modules/@loaders.gl/draco": { 604 | "version": "3.4.6", 605 | "resolved": "https://registry.npmjs.org/@loaders.gl/draco/-/draco-3.4.6.tgz", 606 | "integrity": "sha512-FoxmvM0ojT1B5yntyQ/mzrWN55XyOOqPiie99Bs8yLj9+eNAfQoviMfrED1uS6gYVJEHNBmH9wibNaa1LjMTmw==", 607 | "dependencies": { 608 | "@babel/runtime": "^7.3.1", 609 | "@loaders.gl/loader-utils": "3.4.6", 610 | "@loaders.gl/schema": "3.4.6", 611 | "@loaders.gl/worker-utils": "3.4.6", 612 | "draco3d": "1.5.5" 613 | } 614 | }, 615 | "node_modules/@loaders.gl/gis": { 616 | "version": "3.4.6", 617 | "resolved": "https://registry.npmjs.org/@loaders.gl/gis/-/gis-3.4.6.tgz", 618 | "integrity": "sha512-DKG1oBjz7KYe/VInST3Hsnzo+E3cAv9cOvS6EA34YRMSb1T4xOmdvTpoN6x5/WZU7VBTK376F7TidMNskKOMoA==", 619 | "dependencies": { 620 | "@loaders.gl/loader-utils": "3.4.6", 621 | "@loaders.gl/schema": "3.4.6", 622 | "@mapbox/vector-tile": "^1.3.1", 623 | "@math.gl/polygon": "^3.5.1", 624 | "pbf": "^3.2.1" 625 | } 626 | }, 627 | "node_modules/@loaders.gl/gltf": { 628 | "version": "3.4.6", 629 | "resolved": "https://registry.npmjs.org/@loaders.gl/gltf/-/gltf-3.4.6.tgz", 630 | "integrity": "sha512-BB2Hkz8dTr6IbgccGb6y9QYdXyqbi5L8qIlEldA3P7f36y9EN1JVTBUxyF8hHqPt3YKgJ0RKX9F2YLRrhWT1gw==", 631 | "dependencies": { 632 | "@loaders.gl/draco": "3.4.6", 633 | "@loaders.gl/images": "3.4.6", 634 | "@loaders.gl/loader-utils": "3.4.6", 635 | "@loaders.gl/textures": "3.4.6", 636 | "@math.gl/core": "^3.5.1" 637 | } 638 | }, 639 | "node_modules/@loaders.gl/images": { 640 | "version": "3.4.6", 641 | "resolved": "https://registry.npmjs.org/@loaders.gl/images/-/images-3.4.6.tgz", 642 | "integrity": "sha512-zwM6lXATGxxIe27X1gPyqcgXb6ql9gPkoNlb5pWOrF1D8DrFFjTJSLV9p6WGrVKMZKeioJ2PK8ZnkeRiOYkveA==", 643 | "dependencies": { 644 | "@loaders.gl/loader-utils": "3.4.6" 645 | } 646 | }, 647 | "node_modules/@loaders.gl/loader-utils": { 648 | "version": "3.4.6", 649 | "resolved": "https://registry.npmjs.org/@loaders.gl/loader-utils/-/loader-utils-3.4.6.tgz", 650 | "integrity": "sha512-AN56Tvomas7bOZlrMEDforJWwS6DuXXFT/MsxOR/2vvzhutLDxYSuG4dZ9g5ejqJkiboDLAL3aghXXWekyToaw==", 651 | "dependencies": { 652 | "@babel/runtime": "^7.3.1", 653 | "@loaders.gl/worker-utils": "3.4.6", 654 | "@probe.gl/stats": "^4.0.1" 655 | } 656 | }, 657 | "node_modules/@loaders.gl/loader-utils/node_modules/@probe.gl/stats": { 658 | "version": "4.0.4", 659 | "resolved": "https://registry.npmjs.org/@probe.gl/stats/-/stats-4.0.4.tgz", 660 | "integrity": "sha512-SDuSY/D4yDL6LQDa69l/GCcnZLRiGYdyvYkxWb0CgnzTPdPrcdrzGkzkvpC3zsA4fEFw2smlDje370QGHwlisg==", 661 | "dependencies": { 662 | "@babel/runtime": "^7.0.0" 663 | } 664 | }, 665 | "node_modules/@loaders.gl/math": { 666 | "version": "3.4.6", 667 | "resolved": "https://registry.npmjs.org/@loaders.gl/math/-/math-3.4.6.tgz", 668 | "integrity": "sha512-FC+BSp6NqMH372wkVS92yb+YIP2a26Mi1nEj8eiyRadxkQoyZ2bKH2kxoNX40yCo1xk/ZyX2v8wYq3ZNS+9fIg==", 669 | "dependencies": { 670 | "@loaders.gl/images": "3.4.6", 671 | "@loaders.gl/loader-utils": "3.4.6", 672 | "@math.gl/core": "^3.5.1" 673 | } 674 | }, 675 | "node_modules/@loaders.gl/mvt": { 676 | "version": "3.4.6", 677 | "resolved": "https://registry.npmjs.org/@loaders.gl/mvt/-/mvt-3.4.6.tgz", 678 | "integrity": "sha512-fzZjuY5mS7p3IBu5MSyiHAvRUz2MEX1w0tRW/AlNiBn3SaEKqt8rei7Fir7QTNxK5qEBoTUDr5jOg1wH9SCC7Q==", 679 | "dependencies": { 680 | "@loaders.gl/gis": "3.4.6", 681 | "@loaders.gl/loader-utils": "3.4.6", 682 | "@loaders.gl/schema": "3.4.6", 683 | "@math.gl/polygon": "^3.5.1", 684 | "pbf": "^3.2.1" 685 | } 686 | }, 687 | "node_modules/@loaders.gl/schema": { 688 | "version": "3.4.6", 689 | "resolved": "https://registry.npmjs.org/@loaders.gl/schema/-/schema-3.4.6.tgz", 690 | "integrity": "sha512-uvToDknGCEL0TIZY1Rn76lQ0m22kUtVxE0HbgfgzwkT7dlXeT92F5yD4VVVL8qTX4oqh2xUySPQIaiAqdkGCvg==", 691 | "dependencies": { 692 | "@types/geojson": "^7946.0.7" 693 | } 694 | }, 695 | "node_modules/@loaders.gl/terrain": { 696 | "version": "3.4.6", 697 | "resolved": "https://registry.npmjs.org/@loaders.gl/terrain/-/terrain-3.4.6.tgz", 698 | "integrity": "sha512-Ki/t1wtroBqvPf1XxKdVKWjZ8BwEw4mxIHbWg+vRauxU7T3m85Bfp1KMF49E8jAa5HGikenD2Qumf5jC66GNSQ==", 699 | "dependencies": { 700 | "@babel/runtime": "^7.3.1", 701 | "@loaders.gl/images": "3.4.6", 702 | "@loaders.gl/loader-utils": "3.4.6", 703 | "@loaders.gl/schema": "3.4.6", 704 | "@mapbox/martini": "^0.2.0" 705 | } 706 | }, 707 | "node_modules/@loaders.gl/textures": { 708 | "version": "3.4.6", 709 | "resolved": "https://registry.npmjs.org/@loaders.gl/textures/-/textures-3.4.6.tgz", 710 | "integrity": "sha512-eeYFD0kWwkKwUWQ/sNHMP0wDiG2XsTWPY4rWV9RZRY955p+7q11Xoksqc3M4g8/DJ5+gYnBHyJMM3Tg4cG5Uhg==", 711 | "dependencies": { 712 | "@loaders.gl/images": "3.4.6", 713 | "@loaders.gl/loader-utils": "3.4.6", 714 | "@loaders.gl/schema": "3.4.6", 715 | "@loaders.gl/worker-utils": "3.4.6", 716 | "ktx-parse": "^0.0.4", 717 | "texture-compressor": "^1.0.2" 718 | } 719 | }, 720 | "node_modules/@loaders.gl/tiles": { 721 | "version": "3.4.6", 722 | "resolved": "https://registry.npmjs.org/@loaders.gl/tiles/-/tiles-3.4.6.tgz", 723 | "integrity": "sha512-Tl9H9Gt8p8ZOJGdWjkdAHXjyr3UAArimC/DRRHbP70Zpipgo/qgSfYPbkGih20dvuoj4uuNe9pwSrk9ctmpxMg==", 724 | "dependencies": { 725 | "@loaders.gl/loader-utils": "3.4.6", 726 | "@loaders.gl/math": "3.4.6", 727 | "@math.gl/core": "^3.5.1", 728 | "@math.gl/culling": "^3.5.1", 729 | "@math.gl/geospatial": "^3.5.1", 730 | "@math.gl/web-mercator": "^3.5.1", 731 | "@probe.gl/stats": "^4.0.1" 732 | }, 733 | "peerDependencies": { 734 | "@loaders.gl/core": "^3.4.0" 735 | } 736 | }, 737 | "node_modules/@loaders.gl/tiles/node_modules/@probe.gl/stats": { 738 | "version": "4.0.4", 739 | "resolved": "https://registry.npmjs.org/@probe.gl/stats/-/stats-4.0.4.tgz", 740 | "integrity": "sha512-SDuSY/D4yDL6LQDa69l/GCcnZLRiGYdyvYkxWb0CgnzTPdPrcdrzGkzkvpC3zsA4fEFw2smlDje370QGHwlisg==", 741 | "dependencies": { 742 | "@babel/runtime": "^7.0.0" 743 | } 744 | }, 745 | "node_modules/@loaders.gl/wms": { 746 | "version": "3.4.6", 747 | "resolved": "https://registry.npmjs.org/@loaders.gl/wms/-/wms-3.4.6.tgz", 748 | "integrity": "sha512-LkVaIM36Nqp8rTmeSVnHxHXdq8NRjnoXC0bSoDW3WzClYIcQmMf43zHzi2zQf0Y1O/DH+6oLo9ueOtGKc8VfLA==", 749 | "dependencies": { 750 | "@babel/runtime": "^7.3.1", 751 | "@loaders.gl/images": "3.4.6", 752 | "@loaders.gl/loader-utils": "3.4.6", 753 | "@loaders.gl/schema": "3.4.6", 754 | "@loaders.gl/xml": "3.4.6", 755 | "@turf/rewind": "^5.1.5", 756 | "deep-strict-equal": "^0.2.0", 757 | "lerc": "^4.0.1" 758 | } 759 | }, 760 | "node_modules/@loaders.gl/worker-utils": { 761 | "version": "3.4.6", 762 | "resolved": "https://registry.npmjs.org/@loaders.gl/worker-utils/-/worker-utils-3.4.6.tgz", 763 | "integrity": "sha512-1Ns2d5HbJ22u9PDfEqoDWhg2F3zyYZUCQBmfmSW9Yuxblt2M0pRyB01VvAhPCnLovldvesHu+o16FsgkqieybQ==", 764 | "dependencies": { 765 | "@babel/runtime": "^7.3.1" 766 | } 767 | }, 768 | "node_modules/@loaders.gl/xml": { 769 | "version": "3.4.6", 770 | "resolved": "https://registry.npmjs.org/@loaders.gl/xml/-/xml-3.4.6.tgz", 771 | "integrity": "sha512-kB3R2Wz9d/UEDka5Fhjv/MoIXK2dB57J7nQIXmFpdCVJKPUIm9aZXyqODcCMNoufSR2PI5uqxJ12a14vV3WZsQ==", 772 | "dependencies": { 773 | "@babel/runtime": "^7.3.1", 774 | "@loaders.gl/loader-utils": "3.4.6", 775 | "@loaders.gl/schema": "3.4.6", 776 | "fast-xml-parser": "^4.1.3" 777 | } 778 | }, 779 | "node_modules/@luma.gl/constants": { 780 | "version": "8.5.20", 781 | "resolved": "https://registry.npmjs.org/@luma.gl/constants/-/constants-8.5.20.tgz", 782 | "integrity": "sha512-5yG+ybkUZ4j6kLPWMZjN4Hun2yLB0MyEpNCRKAUN9/yS9UIWA7unyVxjSf2vnE7k/7dywtxlbXegASNFgNVGxw==" 783 | }, 784 | "node_modules/@luma.gl/core": { 785 | "version": "8.5.20", 786 | "resolved": "https://registry.npmjs.org/@luma.gl/core/-/core-8.5.20.tgz", 787 | "integrity": "sha512-xJr96G6vhYcznYHC84fbeOG3fgNM4lFwj9bd0VPcg/Kfe8otUeN1Hl0AKHCCtNn48PiMSg3LKbaiRfNUMhaffQ==", 788 | "dependencies": { 789 | "@babel/runtime": "^7.0.0", 790 | "@luma.gl/constants": "8.5.20", 791 | "@luma.gl/engine": "8.5.20", 792 | "@luma.gl/gltools": "8.5.20", 793 | "@luma.gl/shadertools": "8.5.20", 794 | "@luma.gl/webgl": "8.5.20" 795 | } 796 | }, 797 | "node_modules/@luma.gl/engine": { 798 | "version": "8.5.20", 799 | "resolved": "https://registry.npmjs.org/@luma.gl/engine/-/engine-8.5.20.tgz", 800 | "integrity": "sha512-+0ryJ/4gL1pWaEgZimY21jUPt1LYiO6Cqte8TNUprCfAHoAStsuzD7jwgEqnM6jJOUEdIxQ3w0z3Dzw/0KIE+w==", 801 | "dependencies": { 802 | "@babel/runtime": "^7.0.0", 803 | "@luma.gl/constants": "8.5.20", 804 | "@luma.gl/gltools": "8.5.20", 805 | "@luma.gl/shadertools": "8.5.20", 806 | "@luma.gl/webgl": "8.5.20", 807 | "@math.gl/core": "^3.5.0", 808 | "@probe.gl/env": "^3.5.0", 809 | "@probe.gl/stats": "^3.5.0", 810 | "@types/offscreencanvas": "^2019.7.0" 811 | } 812 | }, 813 | "node_modules/@luma.gl/experimental": { 814 | "version": "8.5.20", 815 | "resolved": "https://registry.npmjs.org/@luma.gl/experimental/-/experimental-8.5.20.tgz", 816 | "integrity": "sha512-V1Jp68rYMPtwMdf+50r3NSYsGV3srjwZ+lcK2ew4DshjedDbYwLqTGMWcOyBhY3K3aCl2LH3Fhn0hAY+3NTLGA==", 817 | "dependencies": { 818 | "@luma.gl/constants": "8.5.20", 819 | "@math.gl/core": "^3.5.0", 820 | "earcut": "^2.0.6" 821 | }, 822 | "peerDependencies": { 823 | "@loaders.gl/gltf": "^3.0.0", 824 | "@loaders.gl/images": "^3.0.0", 825 | "@luma.gl/engine": "^8.4.0", 826 | "@luma.gl/gltools": "^8.4.0", 827 | "@luma.gl/shadertools": "^8.4.0", 828 | "@luma.gl/webgl": "^8.4.0" 829 | } 830 | }, 831 | "node_modules/@luma.gl/gltools": { 832 | "version": "8.5.20", 833 | "resolved": "https://registry.npmjs.org/@luma.gl/gltools/-/gltools-8.5.20.tgz", 834 | "integrity": "sha512-5pP6ph9FSX5gHiVWQM1DmYRUnriklzKUG9yaqlQsKEqCFsOcKB0EfK3MfBVXIfsOdP/1bJZ9Dlz/zV19soWVhg==", 835 | "dependencies": { 836 | "@babel/runtime": "^7.0.0", 837 | "@luma.gl/constants": "8.5.20", 838 | "@probe.gl/env": "^3.5.0", 839 | "@probe.gl/log": "^3.5.0", 840 | "@types/offscreencanvas": "^2019.7.0" 841 | } 842 | }, 843 | "node_modules/@luma.gl/shadertools": { 844 | "version": "8.5.20", 845 | "resolved": "https://registry.npmjs.org/@luma.gl/shadertools/-/shadertools-8.5.20.tgz", 846 | "integrity": "sha512-q1lrCZy1ncIFb4mMjsYgISLzNP6eMnhLUY+Oltj/qjAMcPEssCeHN2+XGfP/CVtU+O7sC+5JY2bQGaTs6HQ/Qw==", 847 | "dependencies": { 848 | "@babel/runtime": "^7.0.0", 849 | "@math.gl/core": "^3.5.0" 850 | } 851 | }, 852 | "node_modules/@luma.gl/webgl": { 853 | "version": "8.5.20", 854 | "resolved": "https://registry.npmjs.org/@luma.gl/webgl/-/webgl-8.5.20.tgz", 855 | "integrity": "sha512-p/kt9KztywH4l+09XHoZ4cPFOoE7xlZXIBMT8rxRVgfe1w0lvi7QYh4tOG7gk+iixQ34EyDQacoHCsabdpmqQg==", 856 | "dependencies": { 857 | "@babel/runtime": "^7.0.0", 858 | "@luma.gl/constants": "8.5.20", 859 | "@luma.gl/gltools": "8.5.20", 860 | "@probe.gl/env": "^3.5.0", 861 | "@probe.gl/stats": "^3.5.0" 862 | } 863 | }, 864 | "node_modules/@mapbox/geojson-rewind": { 865 | "version": "0.5.2", 866 | "resolved": "https://registry.npmjs.org/@mapbox/geojson-rewind/-/geojson-rewind-0.5.2.tgz", 867 | "integrity": "sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==", 868 | "dependencies": { 869 | "get-stream": "^6.0.1", 870 | "minimist": "^1.2.6" 871 | }, 872 | "bin": { 873 | "geojson-rewind": "geojson-rewind" 874 | } 875 | }, 876 | "node_modules/@mapbox/jsonlint-lines-primitives": { 877 | "version": "2.0.2", 878 | "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz", 879 | "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==", 880 | "engines": { 881 | "node": ">= 0.6" 882 | } 883 | }, 884 | "node_modules/@mapbox/martini": { 885 | "version": "0.2.0", 886 | "resolved": "https://registry.npmjs.org/@mapbox/martini/-/martini-0.2.0.tgz", 887 | "integrity": "sha512-7hFhtkb0KTLEls+TRw/rWayq5EeHtTaErgm/NskVoXmtgAQu/9D299aeyj6mzAR/6XUnYRp2lU+4IcrYRFjVsQ==" 888 | }, 889 | "node_modules/@mapbox/point-geometry": { 890 | "version": "0.1.0", 891 | "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz", 892 | "integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==" 893 | }, 894 | "node_modules/@mapbox/tiny-sdf": { 895 | "version": "2.0.6", 896 | "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.0.6.tgz", 897 | "integrity": "sha512-qMqa27TLw+ZQz5Jk+RcwZGH7BQf5G/TrutJhspsca/3SHwmgKQ1iq+d3Jxz5oysPVYTGP6aXxCo5Lk9Er6YBAA==" 898 | }, 899 | "node_modules/@mapbox/unitbezier": { 900 | "version": "0.0.1", 901 | "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz", 902 | "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==" 903 | }, 904 | "node_modules/@mapbox/vector-tile": { 905 | "version": "1.3.1", 906 | "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-1.3.1.tgz", 907 | "integrity": "sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==", 908 | "dependencies": { 909 | "@mapbox/point-geometry": "~0.1.0" 910 | } 911 | }, 912 | "node_modules/@mapbox/whoots-js": { 913 | "version": "3.1.0", 914 | "resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz", 915 | "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==", 916 | "engines": { 917 | "node": ">=6.0.0" 918 | } 919 | }, 920 | "node_modules/@maplibre/maplibre-gl-style-spec": { 921 | "version": "19.2.1", 922 | "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-19.2.1.tgz", 923 | "integrity": "sha512-ZVT5QlkVhlxlPav+ca0NO3Moc7EzbHDO2FXW4ic3Q0Vm+TDUw9I8A2EBws7xUUQZf7HQB3kQ+3Jsh5mFLRD4GQ==", 924 | "dependencies": { 925 | "@mapbox/jsonlint-lines-primitives": "~2.0.2", 926 | "@mapbox/point-geometry": "^0.1.0", 927 | "@mapbox/unitbezier": "^0.0.1", 928 | "@types/mapbox__point-geometry": "^0.1.2", 929 | "json-stringify-pretty-compact": "^3.0.0", 930 | "minimist": "^1.2.8", 931 | "rw": "^1.3.3", 932 | "sort-object": "^3.0.3" 933 | }, 934 | "bin": { 935 | "gl-style-format": "dist/gl-style-format.mjs", 936 | "gl-style-migrate": "dist/gl-style-migrate.mjs", 937 | "gl-style-validate": "dist/gl-style-validate.mjs" 938 | } 939 | }, 940 | "node_modules/@math.gl/core": { 941 | "version": "3.6.3", 942 | "resolved": "https://registry.npmjs.org/@math.gl/core/-/core-3.6.3.tgz", 943 | "integrity": "sha512-jBABmDkj5uuuE0dTDmwwss7Cup5ZwQ6Qb7h1pgvtkEutTrhkcv8SuItQNXmF45494yIHeoGue08NlyeY6wxq2A==", 944 | "dependencies": { 945 | "@babel/runtime": "^7.12.0", 946 | "@math.gl/types": "3.6.3", 947 | "gl-matrix": "^3.4.0" 948 | } 949 | }, 950 | "node_modules/@math.gl/culling": { 951 | "version": "3.6.3", 952 | "resolved": "https://registry.npmjs.org/@math.gl/culling/-/culling-3.6.3.tgz", 953 | "integrity": "sha512-3UERXHbaPlM6pnTk2MI7LeQ5CoelDZzDzghTTcv+HdQCZsT/EOEuEdYimETHtSxiyiOmsX2Un65UBLYT/rbKZg==", 954 | "dependencies": { 955 | "@babel/runtime": "^7.12.0", 956 | "@math.gl/core": "3.6.3", 957 | "gl-matrix": "^3.4.0" 958 | } 959 | }, 960 | "node_modules/@math.gl/geospatial": { 961 | "version": "3.6.3", 962 | "resolved": "https://registry.npmjs.org/@math.gl/geospatial/-/geospatial-3.6.3.tgz", 963 | "integrity": "sha512-6xf657lJnaecSarSzn02t0cnsCSkWb+39m4+im96v20dZTrLCWZ2glDQVzfuL91meDnDXjH4oyvynp12Mj5MFg==", 964 | "dependencies": { 965 | "@babel/runtime": "^7.12.0", 966 | "@math.gl/core": "3.6.3", 967 | "gl-matrix": "^3.4.0" 968 | } 969 | }, 970 | "node_modules/@math.gl/polygon": { 971 | "version": "3.6.3", 972 | "resolved": "https://registry.npmjs.org/@math.gl/polygon/-/polygon-3.6.3.tgz", 973 | "integrity": "sha512-FivQ1ZnYcAss1wVifOkHP/ZnlfQy1IL/769uzNtiHxwUbW0kZG3yyOZ9I7fwyzR5Hvqt3ErJKHjSYZr0uVlz5g==", 974 | "dependencies": { 975 | "@math.gl/core": "3.6.3" 976 | } 977 | }, 978 | "node_modules/@math.gl/sun": { 979 | "version": "3.6.3", 980 | "resolved": "https://registry.npmjs.org/@math.gl/sun/-/sun-3.6.3.tgz", 981 | "integrity": "sha512-mrx6CGYYeTNSQttvcw0KVUy+35YDmnjMqpO/o0t06Vcghrt0HNruB/ScRgUSbJrgkbOg1Vcqm23HBd++clzQzw==", 982 | "dependencies": { 983 | "@babel/runtime": "^7.12.0" 984 | } 985 | }, 986 | "node_modules/@math.gl/types": { 987 | "version": "3.6.3", 988 | "resolved": "https://registry.npmjs.org/@math.gl/types/-/types-3.6.3.tgz", 989 | "integrity": "sha512-3uWLVXHY3jQxsXCr/UCNPSc2BG0hNUljhmOBt9l+lNFDp7zHgm0cK2Tw4kj2XfkJy4TgwZTBGwRDQgWEbLbdTA==" 990 | }, 991 | "node_modules/@math.gl/web-mercator": { 992 | "version": "3.6.3", 993 | "resolved": "https://registry.npmjs.org/@math.gl/web-mercator/-/web-mercator-3.6.3.tgz", 994 | "integrity": "sha512-UVrkSOs02YLehKaehrxhAejYMurehIHPfFQvPFZmdJHglHOU4V2cCUApTVEwOksvCp161ypEqVp+9H6mGhTTcw==", 995 | "dependencies": { 996 | "@babel/runtime": "^7.12.0", 997 | "gl-matrix": "^3.4.0" 998 | } 999 | }, 1000 | "node_modules/@probe.gl/env": { 1001 | "version": "3.6.0", 1002 | "resolved": "https://registry.npmjs.org/@probe.gl/env/-/env-3.6.0.tgz", 1003 | "integrity": "sha512-4tTZYUg/8BICC3Yyb9rOeoKeijKbZHRXBEKObrfPmX4sQmYB15ZOUpoVBhAyJkOYVAM8EkPci6Uw5dLCwx2BEQ==", 1004 | "dependencies": { 1005 | "@babel/runtime": "^7.0.0" 1006 | } 1007 | }, 1008 | "node_modules/@probe.gl/log": { 1009 | "version": "3.6.0", 1010 | "resolved": "https://registry.npmjs.org/@probe.gl/log/-/log-3.6.0.tgz", 1011 | "integrity": "sha512-hjpyenpEvOdowgZ1qMeCJxfRD4JkKdlXz0RC14m42Un62NtOT+GpWyKA4LssT0+xyLULCByRAtG2fzZorpIAcA==", 1012 | "dependencies": { 1013 | "@babel/runtime": "^7.0.0", 1014 | "@probe.gl/env": "3.6.0" 1015 | } 1016 | }, 1017 | "node_modules/@probe.gl/stats": { 1018 | "version": "3.6.0", 1019 | "resolved": "https://registry.npmjs.org/@probe.gl/stats/-/stats-3.6.0.tgz", 1020 | "integrity": "sha512-JdALQXB44OP4kUBN/UrQgzbJe4qokbVF4Y8lkIA8iVCFnjVowWIgkD/z/0QO65yELT54tTrtepw1jScjKB+rhQ==", 1021 | "dependencies": { 1022 | "@babel/runtime": "^7.0.0" 1023 | } 1024 | }, 1025 | "node_modules/@turf/boolean-clockwise": { 1026 | "version": "5.1.5", 1027 | "resolved": "https://registry.npmjs.org/@turf/boolean-clockwise/-/boolean-clockwise-5.1.5.tgz", 1028 | "integrity": "sha512-FqbmEEOJ4rU4/2t7FKx0HUWmjFEVqR+NJrFP7ymGSjja2SQ7Q91nnBihGuT+yuHHl6ElMjQ3ttsB/eTmyCycxA==", 1029 | "dependencies": { 1030 | "@turf/helpers": "^5.1.5", 1031 | "@turf/invariant": "^5.1.5" 1032 | } 1033 | }, 1034 | "node_modules/@turf/clone": { 1035 | "version": "5.1.5", 1036 | "resolved": "https://registry.npmjs.org/@turf/clone/-/clone-5.1.5.tgz", 1037 | "integrity": "sha512-//pITsQ8xUdcQ9pVb4JqXiSqG4dos5Q9N4sYFoWghX21tfOV2dhc5TGqYOhnHrQS7RiKQL1vQ48kIK34gQ5oRg==", 1038 | "dependencies": { 1039 | "@turf/helpers": "^5.1.5" 1040 | } 1041 | }, 1042 | "node_modules/@turf/helpers": { 1043 | "version": "5.1.5", 1044 | "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-5.1.5.tgz", 1045 | "integrity": "sha512-/lF+JR+qNDHZ8bF9d+Cp58nxtZWJ3sqFe6n3u3Vpj+/0cqkjk4nXKYBSY0azm+GIYB5mWKxUXvuP/m0ZnKj1bw==" 1046 | }, 1047 | "node_modules/@turf/invariant": { 1048 | "version": "5.2.0", 1049 | "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-5.2.0.tgz", 1050 | "integrity": "sha512-28RCBGvCYsajVkw2EydpzLdcYyhSA77LovuOvgCJplJWaNVyJYH6BOR3HR9w50MEkPqb/Vc/jdo6I6ermlRtQA==", 1051 | "dependencies": { 1052 | "@turf/helpers": "^5.1.5" 1053 | } 1054 | }, 1055 | "node_modules/@turf/meta": { 1056 | "version": "5.2.0", 1057 | "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-5.2.0.tgz", 1058 | "integrity": "sha512-ZjQ3Ii62X9FjnK4hhdsbT+64AYRpaI8XMBMcyftEOGSmPMUVnkbvuv3C9geuElAXfQU7Zk1oWGOcrGOD9zr78Q==", 1059 | "dependencies": { 1060 | "@turf/helpers": "^5.1.5" 1061 | } 1062 | }, 1063 | "node_modules/@turf/rewind": { 1064 | "version": "5.1.5", 1065 | "resolved": "https://registry.npmjs.org/@turf/rewind/-/rewind-5.1.5.tgz", 1066 | "integrity": "sha512-Gdem7JXNu+G4hMllQHXRFRihJl3+pNl7qY+l4qhQFxq+hiU1cQoVFnyoleIqWKIrdK/i2YubaSwc3SCM7N5mMw==", 1067 | "dependencies": { 1068 | "@turf/boolean-clockwise": "^5.1.5", 1069 | "@turf/clone": "^5.1.5", 1070 | "@turf/helpers": "^5.1.5", 1071 | "@turf/invariant": "^5.1.5", 1072 | "@turf/meta": "^5.1.5" 1073 | } 1074 | }, 1075 | "node_modules/@types/geojson": { 1076 | "version": "7946.0.10", 1077 | "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.10.tgz", 1078 | "integrity": "sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA==" 1079 | }, 1080 | "node_modules/@types/hammerjs": { 1081 | "version": "2.0.41", 1082 | "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.41.tgz", 1083 | "integrity": "sha512-ewXv/ceBaJprikMcxCmWU1FKyMAQ2X7a9Gtmzw8fcg2kIePI1crERDM818W+XYrxqdBBOdlf2rm137bU+BltCA==" 1084 | }, 1085 | "node_modules/@types/mapbox__point-geometry": { 1086 | "version": "0.1.2", 1087 | "resolved": "https://registry.npmjs.org/@types/mapbox__point-geometry/-/mapbox__point-geometry-0.1.2.tgz", 1088 | "integrity": "sha512-D0lgCq+3VWV85ey1MZVkE8ZveyuvW5VAfuahVTQRpXFQTxw03SuIf1/K4UQ87MMIXVKzpFjXFiFMZzLj2kU+iA==" 1089 | }, 1090 | "node_modules/@types/mapbox__vector-tile": { 1091 | "version": "1.3.0", 1092 | "resolved": "https://registry.npmjs.org/@types/mapbox__vector-tile/-/mapbox__vector-tile-1.3.0.tgz", 1093 | "integrity": "sha512-kDwVreQO5V4c8yAxzZVQLE5tyWF+IPToAanloQaSnwfXmIcJ7cyOrv8z4Ft4y7PsLYmhWXmON8MBV8RX0Rgr8g==", 1094 | "dependencies": { 1095 | "@types/geojson": "*", 1096 | "@types/mapbox__point-geometry": "*", 1097 | "@types/pbf": "*" 1098 | } 1099 | }, 1100 | "node_modules/@types/offscreencanvas": { 1101 | "version": "2019.7.0", 1102 | "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.0.tgz", 1103 | "integrity": "sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg==" 1104 | }, 1105 | "node_modules/@types/pbf": { 1106 | "version": "3.0.2", 1107 | "resolved": "https://registry.npmjs.org/@types/pbf/-/pbf-3.0.2.tgz", 1108 | "integrity": "sha512-EDrLIPaPXOZqDjrkzxxbX7UlJSeQVgah3i0aA4pOSzmK9zq3BIh7/MZIQxED7slJByvKM4Gc6Hypyu2lJzh3SQ==" 1109 | }, 1110 | "node_modules/argparse": { 1111 | "version": "1.0.10", 1112 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 1113 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 1114 | "dependencies": { 1115 | "sprintf-js": "~1.0.2" 1116 | } 1117 | }, 1118 | "node_modules/arr-union": { 1119 | "version": "3.1.0", 1120 | "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", 1121 | "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", 1122 | "engines": { 1123 | "node": ">=0.10.0" 1124 | } 1125 | }, 1126 | "node_modules/assign-symbols": { 1127 | "version": "1.0.0", 1128 | "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", 1129 | "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", 1130 | "engines": { 1131 | "node": ">=0.10.0" 1132 | } 1133 | }, 1134 | "node_modules/buf-compare": { 1135 | "version": "1.0.1", 1136 | "resolved": "https://registry.npmjs.org/buf-compare/-/buf-compare-1.0.1.tgz", 1137 | "integrity": "sha512-Bvx4xH00qweepGc43xFvMs5BKASXTbHaHm6+kDYIK9p/4iFwjATQkmPKHQSgJZzKbAymhztRbXUf1Nqhzl73/Q==", 1138 | "engines": { 1139 | "node": ">=0.10.0" 1140 | } 1141 | }, 1142 | "node_modules/bytewise": { 1143 | "version": "1.1.0", 1144 | "resolved": "https://registry.npmjs.org/bytewise/-/bytewise-1.1.0.tgz", 1145 | "integrity": "sha512-rHuuseJ9iQ0na6UDhnrRVDh8YnWVlU6xM3VH6q/+yHDeUH2zIhUzP+2/h3LIrhLDBtTqzWpE3p3tP/boefskKQ==", 1146 | "dependencies": { 1147 | "bytewise-core": "^1.2.2", 1148 | "typewise": "^1.0.3" 1149 | } 1150 | }, 1151 | "node_modules/bytewise-core": { 1152 | "version": "1.2.3", 1153 | "resolved": "https://registry.npmjs.org/bytewise-core/-/bytewise-core-1.2.3.tgz", 1154 | "integrity": "sha512-nZD//kc78OOxeYtRlVk8/zXqTB4gf/nlguL1ggWA8FuchMyOxcyHR4QPQZMUmA7czC+YnaBrPUCubqAWe50DaA==", 1155 | "dependencies": { 1156 | "typewise-core": "^1.2" 1157 | } 1158 | }, 1159 | "node_modules/core-assert": { 1160 | "version": "0.2.1", 1161 | "resolved": "https://registry.npmjs.org/core-assert/-/core-assert-0.2.1.tgz", 1162 | "integrity": "sha512-IG97qShIP+nrJCXMCgkNZgH7jZQ4n8RpPyPeXX++T6avR/KhLhgLiHKoEn5Rc1KjfycSfA9DMa6m+4C4eguHhw==", 1163 | "dependencies": { 1164 | "buf-compare": "^1.0.0", 1165 | "is-error": "^2.2.0" 1166 | }, 1167 | "engines": { 1168 | "node": ">=0.10.0" 1169 | } 1170 | }, 1171 | "node_modules/deep-strict-equal": { 1172 | "version": "0.2.0", 1173 | "resolved": "https://registry.npmjs.org/deep-strict-equal/-/deep-strict-equal-0.2.0.tgz", 1174 | "integrity": "sha512-3daSWyvZ/zwJvuMGlzG1O+Ow0YSadGfb3jsh9xoCutv2tWyB9dA4YvR9L9/fSdDZa2dByYQe+TqapSGUrjnkoA==", 1175 | "dependencies": { 1176 | "core-assert": "^0.2.0" 1177 | }, 1178 | "engines": { 1179 | "node": ">=0.10.0" 1180 | } 1181 | }, 1182 | "node_modules/draco3d": { 1183 | "version": "1.5.5", 1184 | "resolved": "https://registry.npmjs.org/draco3d/-/draco3d-1.5.5.tgz", 1185 | "integrity": "sha512-JVuNV0EJzD3LBYhGyIXJLeBID/EVtmFO1ZNhAYflTgiMiAJlbhXQmRRda/azjc8MRVMHh0gqGhiqHUo5dIXM8Q==" 1186 | }, 1187 | "node_modules/earcut": { 1188 | "version": "2.2.4", 1189 | "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", 1190 | "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==" 1191 | }, 1192 | "node_modules/esbuild": { 1193 | "version": "0.18.11", 1194 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.11.tgz", 1195 | "integrity": "sha512-i8u6mQF0JKJUlGR3OdFLKldJQMMs8OqM9Cc3UCi9XXziJ9WERM5bfkHaEAy0YAvPRMgqSW55W7xYn84XtEFTtA==", 1196 | "hasInstallScript": true, 1197 | "bin": { 1198 | "esbuild": "bin/esbuild" 1199 | }, 1200 | "engines": { 1201 | "node": ">=12" 1202 | }, 1203 | "optionalDependencies": { 1204 | "@esbuild/android-arm": "0.18.11", 1205 | "@esbuild/android-arm64": "0.18.11", 1206 | "@esbuild/android-x64": "0.18.11", 1207 | "@esbuild/darwin-arm64": "0.18.11", 1208 | "@esbuild/darwin-x64": "0.18.11", 1209 | "@esbuild/freebsd-arm64": "0.18.11", 1210 | "@esbuild/freebsd-x64": "0.18.11", 1211 | "@esbuild/linux-arm": "0.18.11", 1212 | "@esbuild/linux-arm64": "0.18.11", 1213 | "@esbuild/linux-ia32": "0.18.11", 1214 | "@esbuild/linux-loong64": "0.18.11", 1215 | "@esbuild/linux-mips64el": "0.18.11", 1216 | "@esbuild/linux-ppc64": "0.18.11", 1217 | "@esbuild/linux-riscv64": "0.18.11", 1218 | "@esbuild/linux-s390x": "0.18.11", 1219 | "@esbuild/linux-x64": "0.18.11", 1220 | "@esbuild/netbsd-x64": "0.18.11", 1221 | "@esbuild/openbsd-x64": "0.18.11", 1222 | "@esbuild/sunos-x64": "0.18.11", 1223 | "@esbuild/win32-arm64": "0.18.11", 1224 | "@esbuild/win32-ia32": "0.18.11", 1225 | "@esbuild/win32-x64": "0.18.11" 1226 | } 1227 | }, 1228 | "node_modules/extend-shallow": { 1229 | "version": "2.0.1", 1230 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 1231 | "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", 1232 | "dependencies": { 1233 | "is-extendable": "^0.1.0" 1234 | }, 1235 | "engines": { 1236 | "node": ">=0.10.0" 1237 | } 1238 | }, 1239 | "node_modules/fast-xml-parser": { 1240 | "version": "4.2.5", 1241 | "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz", 1242 | "integrity": "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==", 1243 | "funding": [ 1244 | { 1245 | "type": "paypal", 1246 | "url": "https://paypal.me/naturalintelligence" 1247 | }, 1248 | { 1249 | "type": "github", 1250 | "url": "https://github.com/sponsors/NaturalIntelligence" 1251 | } 1252 | ], 1253 | "dependencies": { 1254 | "strnum": "^1.0.5" 1255 | }, 1256 | "bin": { 1257 | "fxparser": "src/cli/cli.js" 1258 | } 1259 | }, 1260 | "node_modules/geojson-vt": { 1261 | "version": "3.2.1", 1262 | "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-3.2.1.tgz", 1263 | "integrity": "sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==" 1264 | }, 1265 | "node_modules/get-stream": { 1266 | "version": "6.0.1", 1267 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", 1268 | "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", 1269 | "engines": { 1270 | "node": ">=10" 1271 | }, 1272 | "funding": { 1273 | "url": "https://github.com/sponsors/sindresorhus" 1274 | } 1275 | }, 1276 | "node_modules/get-value": { 1277 | "version": "2.0.6", 1278 | "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", 1279 | "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", 1280 | "engines": { 1281 | "node": ">=0.10.0" 1282 | } 1283 | }, 1284 | "node_modules/gl-matrix": { 1285 | "version": "3.4.3", 1286 | "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz", 1287 | "integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==" 1288 | }, 1289 | "node_modules/global-prefix": { 1290 | "version": "3.0.0", 1291 | "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", 1292 | "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", 1293 | "dependencies": { 1294 | "ini": "^1.3.5", 1295 | "kind-of": "^6.0.2", 1296 | "which": "^1.3.1" 1297 | }, 1298 | "engines": { 1299 | "node": ">=6" 1300 | } 1301 | }, 1302 | "node_modules/h3-js": { 1303 | "version": "3.7.2", 1304 | "resolved": "https://registry.npmjs.org/h3-js/-/h3-js-3.7.2.tgz", 1305 | "integrity": "sha512-LPjlHSwB9zQZrMqKloCZmmmt3yZzIK7nqPcXqwU93zT3TtYG6jP4tZBzAPouxut7lLjdFbMQ75wRBiKfpsnY7w==", 1306 | "engines": { 1307 | "node": ">=4", 1308 | "npm": ">=3", 1309 | "yarn": ">=1.3.0" 1310 | } 1311 | }, 1312 | "node_modules/hammerjs": { 1313 | "version": "2.0.8", 1314 | "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz", 1315 | "integrity": "sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==", 1316 | "engines": { 1317 | "node": ">=0.8.0" 1318 | } 1319 | }, 1320 | "node_modules/ieee754": { 1321 | "version": "1.2.1", 1322 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", 1323 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", 1324 | "funding": [ 1325 | { 1326 | "type": "github", 1327 | "url": "https://github.com/sponsors/feross" 1328 | }, 1329 | { 1330 | "type": "patreon", 1331 | "url": "https://www.patreon.com/feross" 1332 | }, 1333 | { 1334 | "type": "consulting", 1335 | "url": "https://feross.org/support" 1336 | } 1337 | ] 1338 | }, 1339 | "node_modules/image-size": { 1340 | "version": "0.7.5", 1341 | "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.7.5.tgz", 1342 | "integrity": "sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g==", 1343 | "bin": { 1344 | "image-size": "bin/image-size.js" 1345 | }, 1346 | "engines": { 1347 | "node": ">=6.9.0" 1348 | } 1349 | }, 1350 | "node_modules/ini": { 1351 | "version": "1.3.8", 1352 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", 1353 | "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" 1354 | }, 1355 | "node_modules/is-error": { 1356 | "version": "2.2.2", 1357 | "resolved": "https://registry.npmjs.org/is-error/-/is-error-2.2.2.tgz", 1358 | "integrity": "sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==" 1359 | }, 1360 | "node_modules/is-extendable": { 1361 | "version": "0.1.1", 1362 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", 1363 | "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", 1364 | "engines": { 1365 | "node": ">=0.10.0" 1366 | } 1367 | }, 1368 | "node_modules/is-plain-object": { 1369 | "version": "2.0.4", 1370 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", 1371 | "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", 1372 | "dependencies": { 1373 | "isobject": "^3.0.1" 1374 | }, 1375 | "engines": { 1376 | "node": ">=0.10.0" 1377 | } 1378 | }, 1379 | "node_modules/isexe": { 1380 | "version": "2.0.0", 1381 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 1382 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" 1383 | }, 1384 | "node_modules/isobject": { 1385 | "version": "3.0.1", 1386 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", 1387 | "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", 1388 | "engines": { 1389 | "node": ">=0.10.0" 1390 | } 1391 | }, 1392 | "node_modules/json-stringify-pretty-compact": { 1393 | "version": "3.0.0", 1394 | "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-3.0.0.tgz", 1395 | "integrity": "sha512-Rc2suX5meI0S3bfdZuA7JMFBGkJ875ApfVyq2WHELjBiiG22My/l7/8zPpH/CfFVQHuVLd8NLR0nv6vi0BYYKA==" 1396 | }, 1397 | "node_modules/kdbush": { 1398 | "version": "4.0.2", 1399 | "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz", 1400 | "integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==" 1401 | }, 1402 | "node_modules/kind-of": { 1403 | "version": "6.0.3", 1404 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", 1405 | "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", 1406 | "engines": { 1407 | "node": ">=0.10.0" 1408 | } 1409 | }, 1410 | "node_modules/ktx-parse": { 1411 | "version": "0.0.4", 1412 | "resolved": "https://registry.npmjs.org/ktx-parse/-/ktx-parse-0.0.4.tgz", 1413 | "integrity": "sha512-LY3nrmfXl+wZZdPxgJ3ZmLvG+wkOZZP3/dr4RbQj1Pk3Qwz44esOOSFFVQJcNWpXAtiNIC66WgXufX/SYgYz6A==" 1414 | }, 1415 | "node_modules/lerc": { 1416 | "version": "4.0.1", 1417 | "resolved": "https://registry.npmjs.org/lerc/-/lerc-4.0.1.tgz", 1418 | "integrity": "sha512-b351eOjY3DKm1H2hDVhXswsd2RCK6bgREBK6Z639ctClOuYXTi9a44l8yO3zm1pYM2o4WrriloTAKgyrb/0EyA==" 1419 | }, 1420 | "node_modules/long": { 1421 | "version": "3.2.0", 1422 | "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", 1423 | "integrity": "sha512-ZYvPPOMqUwPoDsbJaR10iQJYnMuZhRTvHYl62ErLIEX7RgFlziSBUUvrt3OVfc47QlHHpzPZYP17g3Fv7oeJkg==", 1424 | "engines": { 1425 | "node": ">=0.6" 1426 | } 1427 | }, 1428 | "node_modules/maplibre-gl": { 1429 | "version": "3.2.0", 1430 | "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-3.2.0.tgz", 1431 | "integrity": "sha512-TOo/cV9r8Xy3ngbJtY6JUC7rpjpObrsdO5pt14l5OIw4gY1v5XnxWP16VDSe0zRoncFfDCEBDmRwhfEFwtlbvw==", 1432 | "dependencies": { 1433 | "@mapbox/geojson-rewind": "^0.5.2", 1434 | "@mapbox/jsonlint-lines-primitives": "^2.0.2", 1435 | "@mapbox/point-geometry": "^0.1.0", 1436 | "@mapbox/tiny-sdf": "^2.0.6", 1437 | "@mapbox/unitbezier": "^0.0.1", 1438 | "@mapbox/vector-tile": "^1.3.1", 1439 | "@mapbox/whoots-js": "^3.1.0", 1440 | "@maplibre/maplibre-gl-style-spec": "^19.2.1", 1441 | "@types/geojson": "^7946.0.10", 1442 | "@types/mapbox__point-geometry": "^0.1.2", 1443 | "@types/mapbox__vector-tile": "^1.3.0", 1444 | "@types/pbf": "^3.0.2", 1445 | "earcut": "^2.2.4", 1446 | "geojson-vt": "^3.2.1", 1447 | "gl-matrix": "^3.4.3", 1448 | "global-prefix": "^3.0.0", 1449 | "kdbush": "^4.0.2", 1450 | "murmurhash-js": "^1.0.0", 1451 | "pbf": "^3.2.1", 1452 | "potpack": "^2.0.0", 1453 | "quickselect": "^2.0.0", 1454 | "supercluster": "^8.0.1", 1455 | "tinyqueue": "^2.0.3", 1456 | "vt-pbf": "^3.1.3" 1457 | }, 1458 | "engines": { 1459 | "node": ">=16.14.0", 1460 | "npm": ">=8.1.0" 1461 | }, 1462 | "funding": { 1463 | "url": "https://github.com/maplibre/maplibre-gl-js?sponsor=1" 1464 | } 1465 | }, 1466 | "node_modules/math.gl": { 1467 | "version": "3.6.3", 1468 | "resolved": "https://registry.npmjs.org/math.gl/-/math.gl-3.6.3.tgz", 1469 | "integrity": "sha512-Yq9CyECvSDox9+5ETi2+x1bGTY5WvGUGL3rJfC4KPoCZAM51MGfrCm6rIn4yOJUVfMPs2a5RwMD+yGS/n1g3gg==", 1470 | "dependencies": { 1471 | "@math.gl/core": "3.6.3" 1472 | } 1473 | }, 1474 | "node_modules/minimist": { 1475 | "version": "1.2.8", 1476 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", 1477 | "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", 1478 | "funding": { 1479 | "url": "https://github.com/sponsors/ljharb" 1480 | } 1481 | }, 1482 | "node_modules/mjolnir.js": { 1483 | "version": "2.7.1", 1484 | "resolved": "https://registry.npmjs.org/mjolnir.js/-/mjolnir.js-2.7.1.tgz", 1485 | "integrity": "sha512-72BeUWgTv2cj5aZQKpwL8caNUFhXZ9bDm1hxpNj70XJQ62IBnTZmtv/WPxJvtaVNhzNo+D2U8O6ryNI0zImYcw==", 1486 | "dependencies": { 1487 | "@types/hammerjs": "^2.0.41", 1488 | "hammerjs": "^2.0.8" 1489 | }, 1490 | "engines": { 1491 | "node": ">= 4", 1492 | "npm": ">= 3" 1493 | } 1494 | }, 1495 | "node_modules/murmurhash-js": { 1496 | "version": "1.0.0", 1497 | "resolved": "https://registry.npmjs.org/murmurhash-js/-/murmurhash-js-1.0.0.tgz", 1498 | "integrity": "sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==" 1499 | }, 1500 | "node_modules/node-fetch": { 1501 | "version": "2.6.12", 1502 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", 1503 | "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", 1504 | "dependencies": { 1505 | "whatwg-url": "^5.0.0" 1506 | }, 1507 | "engines": { 1508 | "node": "4.x || >=6.0.0" 1509 | }, 1510 | "peerDependencies": { 1511 | "encoding": "^0.1.0" 1512 | }, 1513 | "peerDependenciesMeta": { 1514 | "encoding": { 1515 | "optional": true 1516 | } 1517 | } 1518 | }, 1519 | "node_modules/pbf": { 1520 | "version": "3.2.1", 1521 | "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.2.1.tgz", 1522 | "integrity": "sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==", 1523 | "dependencies": { 1524 | "ieee754": "^1.1.12", 1525 | "resolve-protobuf-schema": "^2.1.0" 1526 | }, 1527 | "bin": { 1528 | "pbf": "bin/pbf" 1529 | } 1530 | }, 1531 | "node_modules/potpack": { 1532 | "version": "2.0.0", 1533 | "resolved": "https://registry.npmjs.org/potpack/-/potpack-2.0.0.tgz", 1534 | "integrity": "sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw==" 1535 | }, 1536 | "node_modules/protocol-buffers-schema": { 1537 | "version": "3.6.0", 1538 | "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz", 1539 | "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==" 1540 | }, 1541 | "node_modules/quickselect": { 1542 | "version": "2.0.0", 1543 | "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", 1544 | "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==" 1545 | }, 1546 | "node_modules/regenerator-runtime": { 1547 | "version": "0.13.11", 1548 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", 1549 | "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" 1550 | }, 1551 | "node_modules/resolve-protobuf-schema": { 1552 | "version": "2.1.0", 1553 | "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", 1554 | "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", 1555 | "dependencies": { 1556 | "protocol-buffers-schema": "^3.3.1" 1557 | } 1558 | }, 1559 | "node_modules/rw": { 1560 | "version": "1.3.3", 1561 | "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", 1562 | "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" 1563 | }, 1564 | "node_modules/set-value": { 1565 | "version": "2.0.1", 1566 | "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", 1567 | "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", 1568 | "dependencies": { 1569 | "extend-shallow": "^2.0.1", 1570 | "is-extendable": "^0.1.1", 1571 | "is-plain-object": "^2.0.3", 1572 | "split-string": "^3.0.1" 1573 | }, 1574 | "engines": { 1575 | "node": ">=0.10.0" 1576 | } 1577 | }, 1578 | "node_modules/sort-asc": { 1579 | "version": "0.2.0", 1580 | "resolved": "https://registry.npmjs.org/sort-asc/-/sort-asc-0.2.0.tgz", 1581 | "integrity": "sha512-umMGhjPeHAI6YjABoSTrFp2zaBtXBej1a0yKkuMUyjjqu6FJsTF+JYwCswWDg+zJfk/5npWUUbd33HH/WLzpaA==", 1582 | "engines": { 1583 | "node": ">=0.10.0" 1584 | } 1585 | }, 1586 | "node_modules/sort-desc": { 1587 | "version": "0.2.0", 1588 | "resolved": "https://registry.npmjs.org/sort-desc/-/sort-desc-0.2.0.tgz", 1589 | "integrity": "sha512-NqZqyvL4VPW+RAxxXnB8gvE1kyikh8+pR+T+CXLksVRN9eiQqkQlPwqWYU0mF9Jm7UnctShlxLyAt1CaBOTL1w==", 1590 | "engines": { 1591 | "node": ">=0.10.0" 1592 | } 1593 | }, 1594 | "node_modules/sort-object": { 1595 | "version": "3.0.3", 1596 | "resolved": "https://registry.npmjs.org/sort-object/-/sort-object-3.0.3.tgz", 1597 | "integrity": "sha512-nK7WOY8jik6zaG9CRwZTaD5O7ETWDLZYMM12pqY8htll+7dYeqGfEUPcUBHOpSJg2vJOrvFIY2Dl5cX2ih1hAQ==", 1598 | "dependencies": { 1599 | "bytewise": "^1.1.0", 1600 | "get-value": "^2.0.2", 1601 | "is-extendable": "^0.1.1", 1602 | "sort-asc": "^0.2.0", 1603 | "sort-desc": "^0.2.0", 1604 | "union-value": "^1.0.1" 1605 | }, 1606 | "engines": { 1607 | "node": ">=0.10.0" 1608 | } 1609 | }, 1610 | "node_modules/split-string": { 1611 | "version": "3.1.0", 1612 | "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", 1613 | "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", 1614 | "dependencies": { 1615 | "extend-shallow": "^3.0.0" 1616 | }, 1617 | "engines": { 1618 | "node": ">=0.10.0" 1619 | } 1620 | }, 1621 | "node_modules/split-string/node_modules/extend-shallow": { 1622 | "version": "3.0.2", 1623 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", 1624 | "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", 1625 | "dependencies": { 1626 | "assign-symbols": "^1.0.0", 1627 | "is-extendable": "^1.0.1" 1628 | }, 1629 | "engines": { 1630 | "node": ">=0.10.0" 1631 | } 1632 | }, 1633 | "node_modules/split-string/node_modules/is-extendable": { 1634 | "version": "1.0.1", 1635 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", 1636 | "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", 1637 | "dependencies": { 1638 | "is-plain-object": "^2.0.4" 1639 | }, 1640 | "engines": { 1641 | "node": ">=0.10.0" 1642 | } 1643 | }, 1644 | "node_modules/sprintf-js": { 1645 | "version": "1.0.3", 1646 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 1647 | "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" 1648 | }, 1649 | "node_modules/strnum": { 1650 | "version": "1.0.5", 1651 | "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", 1652 | "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" 1653 | }, 1654 | "node_modules/supercluster": { 1655 | "version": "8.0.1", 1656 | "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-8.0.1.tgz", 1657 | "integrity": "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==", 1658 | "dependencies": { 1659 | "kdbush": "^4.0.2" 1660 | } 1661 | }, 1662 | "node_modules/texture-compressor": { 1663 | "version": "1.0.2", 1664 | "resolved": "https://registry.npmjs.org/texture-compressor/-/texture-compressor-1.0.2.tgz", 1665 | "integrity": "sha512-dStVgoaQ11mA5htJ+RzZ51ZxIZqNOgWKAIvtjLrW1AliQQLCmrDqNzQZ8Jh91YealQ95DXt4MEduLzJmbs6lig==", 1666 | "dependencies": { 1667 | "argparse": "^1.0.10", 1668 | "image-size": "^0.7.4" 1669 | }, 1670 | "bin": { 1671 | "texture-compressor": "bin/texture-compressor.js" 1672 | } 1673 | }, 1674 | "node_modules/tinyqueue": { 1675 | "version": "2.0.3", 1676 | "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz", 1677 | "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==" 1678 | }, 1679 | "node_modules/tr46": { 1680 | "version": "0.0.3", 1681 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", 1682 | "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" 1683 | }, 1684 | "node_modules/typewise": { 1685 | "version": "1.0.3", 1686 | "resolved": "https://registry.npmjs.org/typewise/-/typewise-1.0.3.tgz", 1687 | "integrity": "sha512-aXofE06xGhaQSPzt8hlTY+/YWQhm9P0jYUp1f2XtmW/3Bk0qzXcyFWAtPoo2uTGQj1ZwbDuSyuxicq+aDo8lCQ==", 1688 | "dependencies": { 1689 | "typewise-core": "^1.2.0" 1690 | } 1691 | }, 1692 | "node_modules/typewise-core": { 1693 | "version": "1.2.0", 1694 | "resolved": "https://registry.npmjs.org/typewise-core/-/typewise-core-1.2.0.tgz", 1695 | "integrity": "sha512-2SCC/WLzj2SbUwzFOzqMCkz5amXLlxtJqDKTICqg30x+2DZxcfZN2MvQZmGfXWKNWaKK9pBPsvkcwv8bF/gxKg==" 1696 | }, 1697 | "node_modules/union-value": { 1698 | "version": "1.0.1", 1699 | "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", 1700 | "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", 1701 | "dependencies": { 1702 | "arr-union": "^3.1.0", 1703 | "get-value": "^2.0.6", 1704 | "is-extendable": "^0.1.1", 1705 | "set-value": "^2.0.1" 1706 | }, 1707 | "engines": { 1708 | "node": ">=0.10.0" 1709 | } 1710 | }, 1711 | "node_modules/vt-pbf": { 1712 | "version": "3.1.3", 1713 | "resolved": "https://registry.npmjs.org/vt-pbf/-/vt-pbf-3.1.3.tgz", 1714 | "integrity": "sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==", 1715 | "dependencies": { 1716 | "@mapbox/point-geometry": "0.1.0", 1717 | "@mapbox/vector-tile": "^1.3.1", 1718 | "pbf": "^3.2.1" 1719 | } 1720 | }, 1721 | "node_modules/webidl-conversions": { 1722 | "version": "3.0.1", 1723 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", 1724 | "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" 1725 | }, 1726 | "node_modules/whatwg-url": { 1727 | "version": "5.0.0", 1728 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", 1729 | "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", 1730 | "dependencies": { 1731 | "tr46": "~0.0.3", 1732 | "webidl-conversions": "^3.0.0" 1733 | } 1734 | }, 1735 | "node_modules/which": { 1736 | "version": "1.3.1", 1737 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 1738 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 1739 | "dependencies": { 1740 | "isexe": "^2.0.0" 1741 | }, 1742 | "bin": { 1743 | "which": "bin/which" 1744 | } 1745 | } 1746 | } 1747 | } 1748 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dem-map", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "npx esbuild --bundle --outfile=./dist/index.js src/index.ts --platform=browser", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "@basemaps/geo": "^6.40.0", 15 | "@basemaps/tiler": "^6.40.0", 16 | "@chunkd/middleware": "^11.0.0", 17 | "@chunkd/source-http": "^11.0.0", 18 | "@cogeotiff/core": "^8.0.0", 19 | "@deck.gl/core": "^8.9.21", 20 | "@deck.gl/geo-layers": "^8.9.21", 21 | "esbuild": "^0.18.11", 22 | "lerc": "^4.0.1", 23 | "maplibre-gl": "^3.2.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/cogs.ts: -------------------------------------------------------------------------------- 1 | import { GoogleTms } from "@basemaps/geo"; 2 | import { CompositionTiff, Tiler } from "@basemaps/tiler"; 3 | import { SourceCache, SourceChunk } from "@chunkd/middleware"; 4 | import { SourceView } from '@chunkd/source'; 5 | import { SourceHttp } from "@chunkd/source-http"; 6 | import { CogTiff } from "@cogeotiff/core"; 7 | import { QuadKey } from "./quadkey.js"; 8 | import { ramp } from "./ramp.js"; 9 | 10 | export const Cogs = { 11 | 'Taranaki2021': [ 12 | [11, 2012, 1267], 13 | [11, 2013, 1266], 14 | [11, 2013, 1267], 15 | [11, 2013, 1268], 16 | [11, 2014, 1265], 17 | [11, 2014, 1266], 18 | [11, 2014, 1267], 19 | [11, 2014, 1268], 20 | [11, 2014, 1269], 21 | [11, 2015, 1265], 22 | [11, 2015, 1266], 23 | [11, 2015, 1267], 24 | [11, 2015, 1268], 25 | [11, 2015, 1269], 26 | [11, 2016, 1264], 27 | [11, 2016, 1265], 28 | [11, 2016, 1266], 29 | [11, 2016, 1267], 30 | [11, 2016, 1268], 31 | [11, 2016, 1269], 32 | [11, 2016, 1270], 33 | [11, 2017, 1263], 34 | [11, 2017, 1264], 35 | [11, 2017, 1265], 36 | [11, 2017, 1266], 37 | [11, 2017, 1267], 38 | [11, 2017, 1268], 39 | [11, 2017, 1269], 40 | [11, 2017, 1270], 41 | [11, 2017, 1271], 42 | [11, 2018, 1263], 43 | [11, 2018, 1264], 44 | [11, 2018, 1265], 45 | [11, 2018, 1266], 46 | [11, 2018, 1267], 47 | [11, 2018, 1268], 48 | [11, 2018, 1269], 49 | [11, 2018, 1270], 50 | [11, 2018, 1271], 51 | [11, 2019, 1265], 52 | [11, 2019, 1266], 53 | [11, 2019, 1269], 54 | [12, 4025, 2533], 55 | [12, 4025, 2536], 56 | [12, 4027, 2538], 57 | [12, 4038, 2537], 58 | [12, 4038, 2540], 59 | [13, 8051, 5065], 60 | [13, 8051, 5074], 61 | [13, 8053, 5076], 62 | [13, 8054, 5063], 63 | [13, 8055, 5062], 64 | [13, 8055, 5063], 65 | [13, 8062, 5080], 66 | [13, 8063, 5080], 67 | [13, 8063, 5081], 68 | [13, 8066, 5084], 69 | [13, 8067, 5084], 70 | [13, 8067, 5085], 71 | [13, 8076, 5068], 72 | [13, 8076, 5082], 73 | [13, 8076, 5083], 74 | [13, 8078, 5080], 75 | ].map(f => QuadKey.fromTile(f[0], f[1], f[2])) 76 | } 77 | const cache = new SourceCache({ size: 64 * 1024 * 1024}) 78 | window['sourceCache'] = cache; 79 | 80 | const chunk = new SourceChunk( {size: 64 * 1024 }) 81 | 82 | function createTiff(path) { 83 | const source = new SourceView(new SourceHttp(path), [chunk, cache]); 84 | (source as any).uri = source.url.href; 85 | return CogTiff.create(source) 86 | } 87 | 88 | const tiffs = new Map>(); 89 | declare const Lerc: any; // FIXME typing 90 | 91 | const emptyBuffer = (type) => { 92 | const raw = new Uint8ClampedArray(256 * 256 * 4) 93 | if (type === 'mapbox') { 94 | for (let i = 0; i < 256 * 256; i++) { 95 | const offset = i * 4; 96 | raw[offset + 3] = 255 97 | 98 | /** mapbox */ 99 | const base = -10_000; 100 | const interval = 0.1; 101 | 102 | const v = (0 - base) / interval 103 | raw[offset + 0] = Math.floor(v / 256 / 256) % 256 104 | raw[offset + 1] = Math.floor(v / 256) % 256 105 | raw[offset + 2] = v % 256 106 | } 107 | return createImageBitmap(new ImageData(raw, 256, 256));; 108 | } 109 | 110 | return createImageBitmap(new ImageData(raw, 256, 256)); 111 | } 112 | 113 | const googleTiler = new Tiler(GoogleTms); 114 | 115 | export async function lercToBuffer(url: string): Promise<{ buffer: Float32Array, width: number, height: number } | null> { 116 | const urlParts = url.split('@'); 117 | const cogParts = urlParts[0].split('#'); 118 | const cogName = cogParts[0].slice('cog+lerc:'.length + 2) 119 | let method = 'mapbox' 120 | if (cogParts[1]) method = cogParts[1] 121 | 122 | const path = urlParts[urlParts.length - 1].split('/') 123 | const z = Number(path[0]); 124 | const x = Number(path[1]); 125 | const y = Number(path[2]); 126 | 127 | const cogs = Cogs[cogName] 128 | if (cogs == null) return null; 129 | const targetTile = QuadKey.fromTile(z, x, y); 130 | 131 | for (const cogQk of cogs) { 132 | if (!targetTile.startsWith(cogQk)) continue; 133 | 134 | const cog = tiffs.get(cogQk) ?? createTiff(`${cogName}/${QuadKey.toZxy(cogQk)}.tiff`) 135 | tiffs.set(cogQk, cog); 136 | 137 | return cog.then(async (tiff) => { 138 | await Lerc.load() 139 | 140 | const tileId = `${z}-${x}-${y}.lerc` 141 | const result = await googleTiler.tile([tiff], x, y, z) 142 | 143 | if (result.length !== 1) { 144 | console.log('non1 result', tileId); 145 | return null 146 | } 147 | const comp = result[0] as CompositionTiff; 148 | 149 | const tile = await tiff.images[comp.source.imageId].getTile(comp.source.x, comp.source.y); 150 | if (tile == null) { 151 | console.log('empty tile', tileId) 152 | return null 153 | } 154 | 155 | 156 | const decoded = Lerc.decode(tile.bytes) 157 | 158 | return { buffer: decoded.pixels[0], width: decoded.width, height: decoded.height } 159 | }) 160 | } 161 | return null; 162 | } 163 | 164 | export async function lercToImage(url: string): Promise { 165 | const urlParts = url.split('@'); 166 | const cogParts = urlParts[0].split('#'); 167 | const cogName = cogParts[0].slice('cog+lerc:'.length + 2) 168 | let method = 'mapbox' 169 | if (cogParts[1]) method = cogParts[1] 170 | 171 | const path = urlParts[urlParts.length - 1].split('/') 172 | const z = Number(path[0]); 173 | const x = Number(path[1]); 174 | const y = Number(path[2]); 175 | 176 | const cogs = Cogs[cogName] 177 | if (cogs == null) return null; 178 | 179 | const tileId = `${z}-${x}-${y}.lerc` 180 | 181 | const ret = await lercToBuffer(url); 182 | if (ret == null) return emptyBuffer(method); 183 | console.time('create:elevation:' + method + ':' + tileId) 184 | 185 | // Convert the DEM into a RGBA picture 186 | const raw = new Uint8ClampedArray(ret.width * ret.height * 4); 187 | const buf = ret.buffer; 188 | 189 | for (let i = 0; i < buf.length; i++) { 190 | let px = buf[i] 191 | 192 | if (method === 'ramp') { 193 | const offset = i * 4; 194 | 195 | const color = ramp.get(px); 196 | raw[offset + 0] = color[0] 197 | raw[offset + 1] = color[1] 198 | raw[offset + 2] = color[2] 199 | raw[offset + 3] = color[3] 200 | continue; 201 | } 202 | 203 | // COG's NoData is -9999, TODO extract this from the LERC metadata 204 | if (px === -9999 || px == 0) px = 0; // NO_DATA ignore 205 | const offset = i * 4; 206 | // Set alpha to full! 207 | raw[offset + 3] = 255 208 | 209 | /** mapbox */ 210 | const base = -10_000; 211 | const interval = 0.1; 212 | 213 | const v = (px - base) / interval 214 | raw[offset + 0] = Math.floor(v / 256 / 256) % 256 215 | raw[offset + 1] = Math.floor(v / 256) % 256 216 | raw[offset + 2] = v % 256 217 | 218 | /** terrarium */ 219 | // const v = px + 32768; 220 | // raw[offset] = (Math.floor(v / 256)); 221 | // raw[offset + 1] = (Math.floor(v % 256)); 222 | // raw[offset + 2] = (Math.floor((v - Math.floor(v)) * 256)); 223 | } 224 | 225 | console.timeEnd('create:elevation:' + method + ':' + tileId) 226 | return await createImageBitmap(new ImageData(raw, ret.width, ret.height)); 227 | } -------------------------------------------------------------------------------- /src/delatin.ts: -------------------------------------------------------------------------------- 1 | // ISC License 2 | 3 | // Copyright(c) 2019, Michael Fogleman, Vladimir Agafonkin 4 | 5 | // Permission to use, copy, modify, and / or distribute this software for any purpose 6 | // with or without fee is hereby granted, provided that the above copyright notice 7 | // and this permission notice appear in all copies. 8 | 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 10 | // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 11 | // FITNESS.IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 12 | // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 13 | // OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 14 | // TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 15 | // THIS SOFTWARE. 16 | 17 | // @ts-nocheck 18 | 19 | /* eslint-disable complexity, max-params, max-statements, max-depth, no-constant-condition */ 20 | export default class Delatin { 21 | constructor(data, width, height = width) { 22 | this.data = data; // height data 23 | this.width = width; 24 | this.height = height; 25 | 26 | this.coords = []; // vertex coordinates (x, y) 27 | this.triangles = []; // mesh triangle indices 28 | 29 | // additional triangle data 30 | this._halfedges = []; 31 | this._candidates = []; 32 | this._queueIndices = []; 33 | 34 | this._queue = []; // queue of added triangles 35 | this._errors = []; 36 | this._rms = []; 37 | this._pending = []; // triangles pending addition to queue 38 | this._pendingLen = 0; 39 | 40 | this._rmsSum = 0; 41 | 42 | const x1 = width - 1; 43 | const y1 = height - 1; 44 | const p0 = this._addPoint(0, 0); 45 | const p1 = this._addPoint(x1, 0); 46 | const p2 = this._addPoint(0, y1); 47 | const p3 = this._addPoint(x1, y1); 48 | 49 | // add initial two triangles 50 | const t0 = this._addTriangle(p3, p0, p2, -1, -1, -1); 51 | this._addTriangle(p0, p3, p1, t0, -1, -1); 52 | this._flush(); 53 | } 54 | 55 | // refine the mesh until its maximum error gets below the given one 56 | run(maxError = 1) { 57 | while (this.getMaxError() > maxError) { 58 | this.refine(); 59 | } 60 | } 61 | 62 | // refine the mesh with a single point 63 | refine() { 64 | this._step(); 65 | this._flush(); 66 | } 67 | 68 | // max error of the current mesh 69 | getMaxError() { 70 | return this._errors[0]; 71 | } 72 | 73 | // root-mean-square deviation of the current mesh 74 | getRMSD() { 75 | return this._rmsSum > 0 ? Math.sqrt(this._rmsSum / (this.width * this.height)) : 0; 76 | } 77 | 78 | // height value at a given position 79 | heightAt(x, y) { 80 | return this.data[this.width * y + x]; 81 | } 82 | 83 | // rasterize and queue all triangles that got added or updated in _step 84 | _flush() { 85 | const coords = this.coords; 86 | for (let i = 0; i < this._pendingLen; i++) { 87 | const t = this._pending[i]; 88 | // rasterize triangle to find maximum pixel error 89 | const a = 2 * this.triangles[t * 3 + 0]; 90 | const b = 2 * this.triangles[t * 3 + 1]; 91 | const c = 2 * this.triangles[t * 3 + 2]; 92 | this._findCandidate( 93 | coords[a], 94 | coords[a + 1], 95 | coords[b], 96 | coords[b + 1], 97 | coords[c], 98 | coords[c + 1], 99 | t 100 | ); 101 | } 102 | this._pendingLen = 0; 103 | } 104 | 105 | // rasterize a triangle, find its max error, and queue it for processing 106 | _findCandidate(p0x, p0y, p1x, p1y, p2x, p2y, t) { 107 | // triangle bounding box 108 | const minX = Math.min(p0x, p1x, p2x); 109 | const minY = Math.min(p0y, p1y, p2y); 110 | const maxX = Math.max(p0x, p1x, p2x); 111 | const maxY = Math.max(p0y, p1y, p2y); 112 | 113 | // forward differencing variables 114 | let w00 = orient(p1x, p1y, p2x, p2y, minX, minY); 115 | let w01 = orient(p2x, p2y, p0x, p0y, minX, minY); 116 | let w02 = orient(p0x, p0y, p1x, p1y, minX, minY); 117 | const a01 = p1y - p0y; 118 | const b01 = p0x - p1x; 119 | const a12 = p2y - p1y; 120 | const b12 = p1x - p2x; 121 | const a20 = p0y - p2y; 122 | const b20 = p2x - p0x; 123 | 124 | // pre-multiplied z values at vertices 125 | const a = orient(p0x, p0y, p1x, p1y, p2x, p2y); 126 | const z0 = this.heightAt(p0x, p0y) / a; 127 | const z1 = this.heightAt(p1x, p1y) / a; 128 | const z2 = this.heightAt(p2x, p2y) / a; 129 | 130 | // iterate over pixels in bounding box 131 | let maxError = 0; 132 | let mx = 0; 133 | let my = 0; 134 | let rms = 0; 135 | for (let y = minY; y <= maxY; y++) { 136 | // compute starting offset 137 | let dx = 0; 138 | if (w00 < 0 && a12 !== 0) { 139 | dx = Math.max(dx, Math.floor(-w00 / a12)); 140 | } 141 | if (w01 < 0 && a20 !== 0) { 142 | dx = Math.max(dx, Math.floor(-w01 / a20)); 143 | } 144 | if (w02 < 0 && a01 !== 0) { 145 | dx = Math.max(dx, Math.floor(-w02 / a01)); 146 | } 147 | 148 | let w0 = w00 + a12 * dx; 149 | let w1 = w01 + a20 * dx; 150 | let w2 = w02 + a01 * dx; 151 | 152 | let wasInside = false; 153 | 154 | for (let x = minX + dx; x <= maxX; x++) { 155 | // check if inside triangle 156 | if (w0 >= 0 && w1 >= 0 && w2 >= 0) { 157 | wasInside = true; 158 | 159 | // compute z using barycentric coordinates 160 | const z = z0 * w0 + z1 * w1 + z2 * w2; 161 | const dz = Math.abs(z - this.heightAt(x, y)); 162 | rms += dz * dz; 163 | if (dz > maxError) { 164 | maxError = dz; 165 | mx = x; 166 | my = y; 167 | } 168 | } else if (wasInside) { 169 | break; 170 | } 171 | 172 | w0 += a12; 173 | w1 += a20; 174 | w2 += a01; 175 | } 176 | 177 | w00 += b12; 178 | w01 += b20; 179 | w02 += b01; 180 | } 181 | 182 | if ((mx === p0x && my === p0y) || (mx === p1x && my === p1y) || (mx === p2x && my === p2y)) { 183 | maxError = 0; 184 | } 185 | 186 | // update triangle metadata 187 | this._candidates[2 * t] = mx; 188 | this._candidates[2 * t + 1] = my; 189 | this._rms[t] = rms; 190 | 191 | // add triangle to priority queue 192 | this._queuePush(t, maxError, rms); 193 | } 194 | 195 | // process the next triangle in the queue, splitting it with a new point 196 | _step() { 197 | // pop triangle with highest error from priority queue 198 | const t = this._queuePop(); 199 | 200 | const e0 = t * 3 + 0; 201 | const e1 = t * 3 + 1; 202 | const e2 = t * 3 + 2; 203 | 204 | const p0 = this.triangles[e0]; 205 | const p1 = this.triangles[e1]; 206 | const p2 = this.triangles[e2]; 207 | 208 | const ax = this.coords[2 * p0]; 209 | const ay = this.coords[2 * p0 + 1]; 210 | const bx = this.coords[2 * p1]; 211 | const by = this.coords[2 * p1 + 1]; 212 | const cx = this.coords[2 * p2]; 213 | const cy = this.coords[2 * p2 + 1]; 214 | const px = this._candidates[2 * t]; 215 | const py = this._candidates[2 * t + 1]; 216 | 217 | const pn = this._addPoint(px, py); 218 | 219 | if (orient(ax, ay, bx, by, px, py) === 0) { 220 | this._handleCollinear(pn, e0); 221 | } else if (orient(bx, by, cx, cy, px, py) === 0) { 222 | this._handleCollinear(pn, e1); 223 | } else if (orient(cx, cy, ax, ay, px, py) === 0) { 224 | this._handleCollinear(pn, e2); 225 | } else { 226 | const h0 = this._halfedges[e0]; 227 | const h1 = this._halfedges[e1]; 228 | const h2 = this._halfedges[e2]; 229 | 230 | const t0 = this._addTriangle(p0, p1, pn, h0, -1, -1, e0); 231 | const t1 = this._addTriangle(p1, p2, pn, h1, -1, t0 + 1); 232 | const t2 = this._addTriangle(p2, p0, pn, h2, t0 + 2, t1 + 1); 233 | 234 | this._legalize(t0); 235 | this._legalize(t1); 236 | this._legalize(t2); 237 | } 238 | } 239 | 240 | // add coordinates for a new vertex 241 | _addPoint(x, y) { 242 | const i = this.coords.length >> 1; 243 | this.coords.push(x, y); 244 | return i; 245 | } 246 | 247 | // add or update a triangle in the mesh 248 | _addTriangle(a, b, c, ab, bc, ca, e = this.triangles.length) { 249 | const t = e / 3; // new triangle index 250 | 251 | // add triangle vertices 252 | this.triangles[e + 0] = a; 253 | this.triangles[e + 1] = b; 254 | this.triangles[e + 2] = c; 255 | 256 | // add triangle halfedges 257 | this._halfedges[e + 0] = ab; 258 | this._halfedges[e + 1] = bc; 259 | this._halfedges[e + 2] = ca; 260 | 261 | // link neighboring halfedges 262 | if (ab >= 0) { 263 | this._halfedges[ab] = e + 0; 264 | } 265 | if (bc >= 0) { 266 | this._halfedges[bc] = e + 1; 267 | } 268 | if (ca >= 0) { 269 | this._halfedges[ca] = e + 2; 270 | } 271 | 272 | // init triangle metadata 273 | this._candidates[2 * t + 0] = 0; 274 | this._candidates[2 * t + 1] = 0; 275 | this._queueIndices[t] = -1; 276 | this._rms[t] = 0; 277 | 278 | // add triangle to pending queue for later rasterization 279 | this._pending[this._pendingLen++] = t; 280 | 281 | // return first halfedge index 282 | return e; 283 | } 284 | 285 | _legalize(a) { 286 | // if the pair of triangles doesn't satisfy the Delaunay condition 287 | // (p1 is inside the circumcircle of [p0, pl, pr]), flip them, 288 | // then do the same check/flip recursively for the new pair of triangles 289 | // 290 | // pl pl 291 | // /||\ / \ 292 | // al/ || \bl al/ \a 293 | // / || \ / \ 294 | // / a||b \ flip /___ar___\ 295 | // p0\ || /p1 => p0\---bl---/p1 296 | // \ || / \ / 297 | // ar\ || /br b\ /br 298 | // \||/ \ / 299 | // pr pr 300 | 301 | const b = this._halfedges[a]; 302 | 303 | if (b < 0) { 304 | return; 305 | } 306 | 307 | const a0 = a - (a % 3); 308 | const b0 = b - (b % 3); 309 | const al = a0 + ((a + 1) % 3); 310 | const ar = a0 + ((a + 2) % 3); 311 | const bl = b0 + ((b + 2) % 3); 312 | const br = b0 + ((b + 1) % 3); 313 | const p0 = this.triangles[ar]; 314 | const pr = this.triangles[a]; 315 | const pl = this.triangles[al]; 316 | const p1 = this.triangles[bl]; 317 | const coords = this.coords; 318 | 319 | if ( 320 | !inCircle( 321 | coords[2 * p0], 322 | coords[2 * p0 + 1], 323 | coords[2 * pr], 324 | coords[2 * pr + 1], 325 | coords[2 * pl], 326 | coords[2 * pl + 1], 327 | coords[2 * p1], 328 | coords[2 * p1 + 1] 329 | ) 330 | ) { 331 | return; 332 | } 333 | 334 | const hal = this._halfedges[al]; 335 | const har = this._halfedges[ar]; 336 | const hbl = this._halfedges[bl]; 337 | const hbr = this._halfedges[br]; 338 | 339 | this._queueRemove(a0 / 3); 340 | this._queueRemove(b0 / 3); 341 | 342 | const t0 = this._addTriangle(p0, p1, pl, -1, hbl, hal, a0); 343 | const t1 = this._addTriangle(p1, p0, pr, t0, har, hbr, b0); 344 | 345 | this._legalize(t0 + 1); 346 | this._legalize(t1 + 2); 347 | } 348 | 349 | // handle a case where new vertex is on the edge of a triangle 350 | _handleCollinear(pn, a) { 351 | const a0 = a - (a % 3); 352 | const al = a0 + ((a + 1) % 3); 353 | const ar = a0 + ((a + 2) % 3); 354 | const p0 = this.triangles[ar]; 355 | const pr = this.triangles[a]; 356 | const pl = this.triangles[al]; 357 | const hal = this._halfedges[al]; 358 | const har = this._halfedges[ar]; 359 | 360 | const b = this._halfedges[a]; 361 | 362 | if (b < 0) { 363 | const t0 = this._addTriangle(pn, p0, pr, -1, har, -1, a0); 364 | const t1 = this._addTriangle(p0, pn, pl, t0, -1, hal); 365 | this._legalize(t0 + 1); 366 | this._legalize(t1 + 2); 367 | return; 368 | } 369 | 370 | const b0 = b - (b % 3); 371 | const bl = b0 + ((b + 2) % 3); 372 | const br = b0 + ((b + 1) % 3); 373 | const p1 = this.triangles[bl]; 374 | const hbl = this._halfedges[bl]; 375 | const hbr = this._halfedges[br]; 376 | 377 | this._queueRemove(b0 / 3); 378 | 379 | const t0 = this._addTriangle(p0, pr, pn, har, -1, -1, a0); 380 | const t1 = this._addTriangle(pr, p1, pn, hbr, -1, t0 + 1, b0); 381 | const t2 = this._addTriangle(p1, pl, pn, hbl, -1, t1 + 1); 382 | const t3 = this._addTriangle(pl, p0, pn, hal, t0 + 2, t2 + 1); 383 | 384 | this._legalize(t0); 385 | this._legalize(t1); 386 | this._legalize(t2); 387 | this._legalize(t3); 388 | } 389 | 390 | // priority queue methods 391 | 392 | _queuePush(t, error, rms) { 393 | const i = this._queue.length; 394 | this._queueIndices[t] = i; 395 | this._queue.push(t); 396 | this._errors.push(error); 397 | this._rmsSum += rms; 398 | this._queueUp(i); 399 | } 400 | 401 | _queuePop() { 402 | const n = this._queue.length - 1; 403 | this._queueSwap(0, n); 404 | this._queueDown(0, n); 405 | return this._queuePopBack(); 406 | } 407 | 408 | _queuePopBack() { 409 | const t = this._queue.pop(); 410 | this._errors.pop(); 411 | this._rmsSum -= this._rms[t]; 412 | this._queueIndices[t] = -1; 413 | return t; 414 | } 415 | 416 | _queueRemove(t) { 417 | const i = this._queueIndices[t]; 418 | if (i < 0) { 419 | const it = this._pending.indexOf(t); 420 | if (it !== -1) { 421 | this._pending[it] = this._pending[--this._pendingLen]; 422 | } else { 423 | throw new Error('Broken triangulation (something went wrong).'); 424 | } 425 | return; 426 | } 427 | const n = this._queue.length - 1; 428 | if (n !== i) { 429 | this._queueSwap(i, n); 430 | if (!this._queueDown(i, n)) { 431 | this._queueUp(i); 432 | } 433 | } 434 | this._queuePopBack(); 435 | } 436 | 437 | _queueLess(i, j) { 438 | return this._errors[i] > this._errors[j]; 439 | } 440 | 441 | _queueSwap(i, j) { 442 | const pi = this._queue[i]; 443 | const pj = this._queue[j]; 444 | this._queue[i] = pj; 445 | this._queue[j] = pi; 446 | this._queueIndices[pi] = j; 447 | this._queueIndices[pj] = i; 448 | const e = this._errors[i]; 449 | this._errors[i] = this._errors[j]; 450 | this._errors[j] = e; 451 | } 452 | 453 | _queueUp(j0) { 454 | let j = j0; 455 | while (true) { 456 | const i = (j - 1) >> 1; 457 | if (i === j || !this._queueLess(j, i)) { 458 | break; 459 | } 460 | this._queueSwap(i, j); 461 | j = i; 462 | } 463 | } 464 | 465 | _queueDown(i0, n) { 466 | let i = i0; 467 | while (true) { 468 | const j1 = 2 * i + 1; 469 | if (j1 >= n || j1 < 0) { 470 | break; 471 | } 472 | const j2 = j1 + 1; 473 | let j = j1; 474 | if (j2 < n && this._queueLess(j2, j1)) { 475 | j = j2; 476 | } 477 | if (!this._queueLess(j, i)) { 478 | break; 479 | } 480 | this._queueSwap(i, j); 481 | i = j; 482 | } 483 | return i > i0; 484 | } 485 | } 486 | 487 | function orient(ax, ay, bx, by, cx, cy) { 488 | return (bx - cx) * (ay - cy) - (by - cy) * (ax - cx); 489 | } 490 | 491 | function inCircle(ax, ay, bx, by, cx, cy, px, py) { 492 | const dx = ax - px; 493 | const dy = ay - py; 494 | const ex = bx - px; 495 | const ey = by - py; 496 | const fx = cx - px; 497 | const fy = cy - py; 498 | 499 | const ap = dx * dx + dy * dy; 500 | const bp = ex * ex + ey * ey; 501 | const cp = fx * fx + fy * fy; 502 | 503 | return dx * (ey * cp - bp * fy) - dy * (ex * cp - bp * fx) + ap * (ex * fy - ey * fx) < 0; 504 | } 505 | -------------------------------------------------------------------------------- /src/index.deck.gl.ts: -------------------------------------------------------------------------------- 1 | import { Deck } from '@deck.gl/core/typed'; 2 | import { MapView } from '@deck.gl/core'; 3 | import { TerrainLayer, TileLayer } from '@deck.gl/geo-layers/typed'; 4 | import { BitmapLayer, PathLayer } from '@deck.gl/layers'; 5 | import { GeoJsonLayer, ArcLayer } from '@deck.gl/layers'; 6 | import * as terrain from '@loaders.gl/terrain' 7 | import { GoogleTms } from '@basemaps/geo'; 8 | import { Tiler } from '@basemaps/tiler'; 9 | import { lercToBuffer, lercToImage } from './cogs.js'; 10 | import Martini from '@mapbox/martini' 11 | import Delatin from './delatin.js' 12 | export type TypedArray = 13 | | Int8Array 14 | | Uint8Array 15 | | Int16Array 16 | | Uint16Array 17 | | Int32Array 18 | | Uint32Array 19 | | Uint8ClampedArray 20 | | Float32Array 21 | | Float64Array; 22 | const martini = new Martini(257) 23 | type BoundingBox = [[number, number, number], [number, number, number]]; 24 | export type MeshAttribute = { 25 | value: TypedArray; 26 | size: number; 27 | byteOffset?: number; 28 | byteStride?: number; 29 | normalized?: boolean; 30 | } 31 | export type MeshAttributes = Record; 32 | 33 | ; 34 | /** 35 | * Get the (axis aligned) bounding box of a mesh 36 | * @param attributes 37 | * @returns array of two vectors representing the axis aligned bounding box 38 | */ 39 | // eslint-disable-next-line complexity 40 | export function getMeshBoundingBox(attributes: MeshAttributes): BoundingBox { 41 | let minX = Infinity; 42 | let minY = Infinity; 43 | let minZ = Infinity; 44 | let maxX = -Infinity; 45 | let maxY = -Infinity; 46 | let maxZ = -Infinity; 47 | 48 | const positions = attributes.POSITION ? attributes.POSITION.value : []; 49 | const len = positions && positions.length; 50 | 51 | for (let i = 0; i < len; i += 3) { 52 | const x = positions[i]; 53 | const y = positions[i + 1]; 54 | const z = positions[i + 2]; 55 | 56 | minX = x < minX ? x : minX; 57 | minY = y < minY ? y : minY; 58 | minZ = z < minZ ? z : minZ; 59 | 60 | maxX = x > maxX ? x : maxX; 61 | maxY = y > maxY ? y : maxY; 62 | maxZ = z > maxZ ? z : maxZ; 63 | } 64 | return [ 65 | [minX, minY, minZ], 66 | [maxX, maxY, maxZ] 67 | ]; 68 | } 69 | 70 | const COUNTRIES = 71 | 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_50m_admin_0_scale_rank.geojson'; //eslint-disable-line 72 | 73 | const googleTiler = new Tiler(GoogleTms); 74 | 75 | function getMeshAttributes( 76 | vertices, 77 | terrain: Float32Array , 78 | width: number, 79 | height: number, 80 | bounds?: number[] 81 | ) { 82 | const gridSize = width ; 83 | const numOfVerticies = vertices.length / 2; 84 | // vec3. x, y in pixels, z in meters 85 | const positions = new Float32Array(numOfVerticies * 3); 86 | // vec2. 1 to 1 relationship with position. represents the uv on the texture image. 0,0 to 1,1. 87 | const texCoords = new Float32Array(numOfVerticies * 2); 88 | 89 | const [minX, minY, maxX, maxY] = bounds || [0, 0, width, height]; 90 | const xScale = (maxX - minX) / width; 91 | const yScale = (maxY - minY) / height; 92 | 93 | for (let i = 0; i < numOfVerticies; i++) { 94 | const x = vertices[i * 2]; 95 | const y = vertices[i * 2 + 1]; 96 | const pixelIdx = y * gridSize + x; 97 | 98 | positions[3 * i + 0] = x * xScale + minX; 99 | positions[3 * i + 1] = -y * yScale + maxY; 100 | positions[3 * i + 2] = terrain[pixelIdx]; 101 | 102 | texCoords[2 * i + 0] = x / width; 103 | texCoords[2 * i + 1] = y / height; 104 | } 105 | 106 | return { 107 | POSITION: {value: positions, size: 3}, 108 | TEXCOORD_0: {value: texCoords, size: 2}, 109 | // NORMAL: {},// - optional, but creates the high poly look with lighting 110 | }; 111 | } 112 | 113 | 114 | const tileLayer = new TileLayer({ 115 | // https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Tile_servers 116 | data: 'https://Taranaki2021#ramp@{z}/{x}/{y}', 117 | 118 | minZoom: 0, 119 | maxZoom: 22, 120 | tileSize: 256, 121 | 122 | async getTileData(props) { 123 | // console.log(props) 124 | 125 | return await lercToImage(props.url?.replace('https', 'cog+lerc')) 126 | // const ret = await fetch(props.url!) 127 | // if (ret.ok) return ret.arrayBuffer(); 128 | // return null; 129 | }, 130 | 131 | renderSubLayers: props => { 132 | // console.log(props) 133 | const { 134 | bbox: {west, south, east, north} 135 | } = props.tile; 136 | 137 | return new BitmapLayer(props, { 138 | data: null, 139 | image: props.data, 140 | bounds: [west, south, east, north] 141 | }); 142 | } 143 | }); 144 | 145 | export function renderToDom() { 146 | const app = document.querySelector('#app'); 147 | const layer = new TerrainLayer({ 148 | id: 'terrain', 149 | 150 | // getTileData(props) { 151 | // console.log('getTile', props) 152 | // }, 153 | 154 | async fetch(url, context) { 155 | if (url.startsWith('https')) return fetch(url); 156 | 157 | const buf = await lercToBuffer(url); 158 | if (buf == null) { 159 | console.log('Nothing'); 160 | throw Error('Missing') 161 | } 162 | const width = buf.width; 163 | const height = buf.height; 164 | 165 | // const tin = new Delatin(buf.buffer, width + 1, height+ 1); 166 | // tin.run(10); 167 | // // @ts-expect-error 168 | // const {coords, triangles} = tin; 169 | // const vertices = coords; 170 | const terrain = new Float32Array((buf.width + 1) * (buf.height + 1)); 171 | for (let i = 0, y = 0; y < height; y++) { 172 | for (let x = 0; x < width; x++, i++) { 173 | // const val = buf.buffer[i]; 174 | terrain[i + y] = buf.buffer[i]; 175 | 176 | } 177 | } 178 | for (let i = (buf.width + 1) * buf.width, x = 0; x < buf.width; x++, i++) { 179 | terrain[i] = terrain[i - buf.width - 1]; 180 | } 181 | // backfill right border 182 | for (let i = buf.height, y = 0; y < buf.height + 1; y++, i += buf.height + 1) { 183 | terrain[i] = terrain[i - 1]; 184 | } 185 | 186 | const tile = martini.createTile(terrain); 187 | const {vertices, triangles} = tile.getMesh(); 188 | 189 | let attributes = getMeshAttributes(vertices, buf.buffer, width, height); 190 | const boundingBox = getMeshBoundingBox(attributes); 191 | console.log(url, width, height) 192 | 193 | // console.log(url, buf.buffer, attributes) 194 | return { 195 | // Data return by this loader implementation 196 | loaderData: { 197 | header: {} 198 | }, 199 | header: { 200 | vertexCount: triangles.length, 201 | boundingBox 202 | }, 203 | mode: 4, // TRIANGLES 204 | indices: {value: Uint32Array.from(triangles), size: 1}, 205 | attributes 206 | }; 207 | }, 208 | minZoom: 0, 209 | maxZoom: 23, 210 | strategy: 'no-overlap', 211 | elevationDecoder: { 212 | rScaler: 6553.6, 213 | gScaler: 25.6, 214 | bScaler: 0.1, 215 | offset: -10000 216 | }, 217 | elevationData: 'cog+lerc://Taranaki2021#@{z}/{x}/{y}', 218 | texture: 'https://basemaps.linz.govt.nz/v1/tiles/aerial/WebMercatorQuad/{z}/{x}/{y}.webp?api=c01h3e17kjsw5evq8ndjxbda80e', 219 | wireframe : false, 220 | color: [255, 255, 255] 221 | }); 222 | 223 | const deck = new Deck({ 224 | canvas: 'deck-canvas', 225 | initialViewState: { 226 | latitude: -39.333, 227 | longitude: 174.0416, 228 | zoom: 11 229 | }, 230 | controller: true, 231 | layers: [ 232 | layer, 233 | // tileLayer, 234 | new GeoJsonLayer({ 235 | id: 'base-map', 236 | data: COUNTRIES, 237 | // Styles 238 | stroked: true, 239 | filled: true, 240 | lineWidthMinPixels: 2, 241 | opacity: 0.4, 242 | getLineColor: [60, 60, 60], 243 | getFillColor: [200, 200, 200] 244 | }), 245 | ] 246 | }) 247 | console.log(deck) 248 | } 249 | 250 | document.addEventListener('DOMContentLoaded', renderToDom); -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import m from 'maplibre-gl'; 2 | import { lercToImage } from './cogs.js'; 3 | 4 | const cancel = { cancel() { } }; 5 | 6 | m.addProtocol('cog+lerc', (req, cb) => { 7 | if (req.type !== 'image') throw new Error('Invalid request type: ' + req.type) 8 | 9 | lercToImage(req.url).then(buf => { 10 | if (buf) return cb(null, buf); 11 | return cb(new Error('Failed'), null); 12 | }) 13 | return cancel 14 | }) 15 | 16 | document.addEventListener('DOMContentLoaded', async () => { 17 | const main = document.querySelector('#main'); 18 | if (main == null) throw new Error('Failed to find #main') 19 | 20 | const style = { 21 | version: 8, 22 | sources: { 23 | linz: { 24 | type: 'raster', 25 | tiles: ['https://basemaps.linz.govt.nz/v1/tiles/aerial/WebMercatorQuad/{z}/{x}/{y}.webp?api=c01h3e17kjsw5evq8ndjxbda80e'], 26 | tileSize: 256, 27 | }, 28 | raster: { 29 | type: 'raster', 30 | tiles: ['cog+lerc://Taranaki2021#ramp@{z}/{x}/{y}'], 31 | tileSize: 256, 32 | minzoom: 10, 33 | maxzoom: 18, 34 | }, 35 | // TODO why do we need both a hillshade and terrain source 36 | // ref : https://maplibre.org/maplibre-gl-js/docs/examples/3d-terrain/ 37 | hillshadeSource: { 38 | type: 'raster-dem', 39 | tiles: ['cog+lerc://Taranaki2021#mapbox@{z}/{x}/{y}'], 40 | tileSize: 256, 41 | encoding: 'mapbox' 42 | }, 43 | terrainSource: { 44 | type: 'raster-dem', 45 | tiles: ['cog+lerc://Taranaki2021#mapbox@{z}/{x}/{y}'], 46 | tileSize: 256, 47 | encoding: 'mapbox' 48 | }, 49 | }, 50 | layers: [ 51 | { id: 'linz', type: 'raster', source: 'linz' }, 52 | ], 53 | terrain: { 54 | source: 'terrainSource', exaggeration: 1 55 | } 56 | } as any 57 | 58 | 59 | const map = new m.Map({ 60 | container: 'main', 61 | zoom: 10, 62 | center: [174.0416, -39.333], 63 | hash: true, 64 | style, 65 | }); 66 | 67 | map.addControl( 68 | new m.NavigationControl({ 69 | visualizePitch: true, 70 | showZoom: true, 71 | showCompass: true 72 | }) 73 | ); 74 | 75 | map.addControl( 76 | new m.TerrainControl({ 77 | source: 'terrainSource', 78 | exaggeration: 1 79 | }) 80 | ); 81 | 82 | 83 | document.querySelector('#color-ramp')?.addEventListener('click', () => { 84 | const ramp = map.getLayer('ramp') 85 | if (ramp) { 86 | map.removeLayer('ramp') 87 | } else { 88 | map.addLayer({ id: 'ramp', type: 'raster', source: 'raster' }, map.getLayer('hillshade') ? 'hillshade' : undefined) 89 | } 90 | }) 91 | 92 | document.querySelector('#hillshade')?.addEventListener('click', () => { 93 | const shade = map.getLayer('hillshade') 94 | if (shade) { 95 | map.removeLayer('hillshade') 96 | } else { 97 | map.addLayer({ 98 | id: 'hillshade', 99 | type: 'hillshade', 100 | source: 'hillshadeSource', 101 | layout: { visibility: 'visible' }, 102 | paint: { 103 | 'hillshade-shadow-color': '#473B24' 104 | } 105 | }) 106 | } 107 | }) 108 | // map.showTileBoundaries = true 109 | window['map'] = map; 110 | }) 111 | -------------------------------------------------------------------------------- /src/quadkey.ts: -------------------------------------------------------------------------------- 1 | 2 | const CHAR_0 = '0'.charCodeAt(0); 3 | const CHAR_1 = '1'.charCodeAt(0); 4 | const CHAR_2 = '2'.charCodeAt(0); 5 | const CHAR_3 = '3'.charCodeAt(0); 6 | 7 | export const QuadKey = { 8 | /** 9 | * Convert a tile location to a quadkey 10 | * @param tile tile to covert 11 | */ 12 | fromTile(z: number, x: number, y: number): string { 13 | let quadKey = ''; 14 | for (let zI = z; zI > 0; zI--) { 15 | let b = CHAR_0; 16 | const mask = 1 << (zI - 1); 17 | if ((x & mask) !== 0) b++; 18 | if ((y & mask) !== 0) b += 2; 19 | quadKey += String.fromCharCode(b); 20 | } 21 | return quadKey; 22 | }, 23 | 24 | toZxy(qk: string): string { 25 | const tile = this.toTile(qk); 26 | return `${tile.z}-${tile.x}-${tile.y}` 27 | }, 28 | 29 | /** 30 | * Convert a quadkey to a XYZ Tile location 31 | * @param quadKey quadkey to convert 32 | */ 33 | toTile(quadKey: string): { z: number, x: number, y: number } { 34 | let x = 0; 35 | let y = 0; 36 | const z = quadKey.length; 37 | 38 | for (let i = z; i > 0; i--) { 39 | const mask = 1 << (i - 1); 40 | const q = quadKey.charCodeAt(z - i); 41 | if (q === CHAR_1) x |= mask; 42 | if (q === CHAR_2) y |= mask; 43 | if (q === CHAR_3) { 44 | x |= mask; 45 | y |= mask; 46 | } 47 | } 48 | return { x, y, z }; 49 | }, 50 | }; -------------------------------------------------------------------------------- /src/ramp.ts: -------------------------------------------------------------------------------- 1 | 2 | export class ColorRamp { 3 | noData: { v: number, color: [number, number, number, number] }; 4 | ramps: { v: number, color: [number, number, number, number] }[] = [] 5 | constructor(ramp: string, noDataValue: number) { 6 | const ramps = ramp.split('\n') 7 | 8 | for (const ramp of ramps) { 9 | const parts = ramp.trim().split(' ') 10 | if (parts[0] == 'nv') { 11 | this.noData = { v: noDataValue, color: parts.slice(1).map(Number) as [number, number, number, number] } 12 | continue; 13 | } 14 | const numbers = parts.map(Number) 15 | this.ramps.push({ v: numbers[0], color: numbers.slice(1) as [number, number, number, number] }); 16 | } 17 | } 18 | 19 | get(num:number): [number, number, number, number] { 20 | if (num === this.noData.v) return this.noData.color; 21 | 22 | const first = this.ramps[0]; 23 | if (num < first[0]) return first[0].color 24 | 25 | for (let i = 0; i < this.ramps.length - 1; i++) { 26 | const ramp = this.ramps[i]; 27 | const rampNext = this.ramps[i + 1]; 28 | if (num >= rampNext.v) continue; 29 | if (num < ramp.v) continue 30 | if (ramp.v == num) return ramp.color; 31 | 32 | const range = rampNext.v - ramp.v 33 | const offset = num - ramp.v; 34 | const scale = offset / range; 35 | 36 | const r = Math.round((rampNext.color[0] - ramp.color[0]) * scale + ramp.color[0]) 37 | const g = Math.round((rampNext.color[1] - ramp.color[1]) * scale + ramp.color[1]) 38 | const b = Math.round((rampNext.color[2] - ramp.color[2]) * scale + ramp.color[2]) 39 | const a = Math.round((rampNext.color[3] - ramp.color[3]) * scale + ramp.color[3]) 40 | 41 | return [r, g, b, a] 42 | } 43 | return this.ramps[this.ramps.length - 1].color 44 | } 45 | } 46 | 47 | // Stolen from https://github.com/andrewharvey/srtm-stylesheets/blob/master/stylesheets/color-ramps/srtm-Australia-color-ramp.gdaldem.txt 48 | export const ramp = new ColorRamp(`nv 0 0 0 0 49 | -8764 0 0 0 255 50 | -4000 3 45 85 255 51 | -100 0 101 199 255 52 | 0 192 224 255 255 53 | 1 108 220 108 255 54 | 55 50 180 50 255 55 | 390 240 250 150 255 56 | 835 190 185 135 255 57 | 1114 180 128 107 255 58 | 1392 235 220 175 255 59 | 2000 215 200 244 255 60 | 4000 255 0 255 255`, -9999) --------------------------------------------------------------------------------