mirror of
https://github.com/MeshCore-Beacon/beacon-web.git
synced 2026-10-22 18:51:21 +00:00
Apply dependabot bumps; migrate to maplibre-gl 6
Named imports, Vite worker URL via setWorkerUrl, and the single missing-image resolver replacing the styleimagemissing listeners.
This commit is contained in:
1 parent
205dad8506
commit
8d963a59b3
8 files changed
+183
-201
No files matched your search
Generated
+140
-169
@@ -13,10 +13,10 @@
|
||||
"@tanstack/react-query": "^5.100.11",
|
||||
"@tanstack/react-virtual": "^3.13.25",
|
||||
"echarts": "6.1.0",
|
||||
"maplibre-gl": "^5.24.0",
|
||||
"maplibre-gl": "^6.9.0",
|
||||
"react": "^19.2.6",
|
||||
"react-dom": "^19.2.6",
|
||||
"react-router-dom": "^7.15.1"
|
||||
"react-router-dom": "^7.18.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^10.0.1",
|
||||
@@ -36,7 +36,7 @@
|
||||
"typescript": "~6.0.2",
|
||||
"typescript-eslint": "^8.59.2",
|
||||
"vite": "^8.0.12",
|
||||
"vitest": "^4.1.7"
|
||||
"vitest": "^4.1.11"
|
||||
}
|
||||
},
|
||||
"node_modules/@adobe/css-tools": {
|
||||
@@ -821,11 +821,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mapbox/jsonlint-lines-primitives": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz",
|
||||
"integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.3.tgz",
|
||||
"integrity": "sha512-0SElaV0uMxEnxzBhhX9WTuPyUeMsAN/SS0i16tjuba4/mio63MG9khjC1a0JAiPGXAwvwm4UfHJURCN7nyudQg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
"node": ">= 22"
|
||||
}
|
||||
},
|
||||
"node_modules/@mapbox/point-geometry": {
|
||||
@@ -841,47 +842,38 @@
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/@mapbox/unitbezier": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz",
|
||||
"integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==",
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-1.0.0.tgz",
|
||||
"integrity": "sha512-fqd515fjBmANKGGsQ286E2Wvj/XvDFpGzwJxq4CI6jMQue6Oy04uCKp+JWKF00xRTmk6cEu1jPJ9p3xqH8YWqQ==",
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/@mapbox/vector-tile": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-2.0.5.tgz",
|
||||
"integrity": "sha512-pXj8m7KTsqZt+1jsE0xIpGvqTSbblfkuEJL/NJmNePMtEwxO8V3XMDo9WMSfDeqHvCtBI9Lmt4mGcGR10zecmw==",
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-3.0.0.tgz",
|
||||
"integrity": "sha512-Qf10S1uIHMk20ri/IVBnpS+esUEkVaR5Hftmz88jTInrpmWgPGJfPe3LVjjlE77trLx8tH6qjTG7uWH9hIq/0Q==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"@mapbox/point-geometry": "~1.1.0",
|
||||
"@types/geojson": "^7946.0.16",
|
||||
"pbf": "^4.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@mapbox/whoots-js": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz",
|
||||
"integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
"pbf": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@maplibre/geojson-vt": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@maplibre/geojson-vt/-/geojson-vt-6.1.0.tgz",
|
||||
"integrity": "sha512-2eIY4gZxeKIVOZVNkAMb+5NgXhgsMQpOveTQAvnp53LYqHGJZDidk7Ew0Tged9PThidpbS+NFTh0g4zivhPDzQ==",
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@maplibre/geojson-vt/-/geojson-vt-6.1.1.tgz",
|
||||
"integrity": "sha512-FVMOcmSP/yqol45t7StApEyTL5/vmqBCuFhH9n+fFuINenhaX+YgHHIt1yJ86S8kln3uJLcMvmEU2cfn6E2eCQ==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"kdbush": "^4.0.2"
|
||||
"kdbush": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@maplibre/maplibre-gl-style-spec": {
|
||||
"version": "24.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-24.10.0.tgz",
|
||||
"integrity": "sha512-lichxSiagMEBBrqHF0trtMQH9RKh+9jUlIJl0qW0QHvt2H/tbvUWdE+ZzI2Jd0/pT7j/iavLonlPu7EQ/ixTOw==",
|
||||
"version": "26.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-26.4.2.tgz",
|
||||
"integrity": "sha512-6J0vZqMZvRAJKtdWJdDGHEh1YJ2ZHG08/GOur8gCArYhO8ZkM//OXqtI2AAEz4jc2G+Wq4MfcePg8qNK5TZ4Kg==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@mapbox/jsonlint-lines-primitives": "~2.0.2",
|
||||
"@mapbox/jsonlint-lines-primitives": "^2.0.3",
|
||||
"@mapbox/unitbezier": "^1.0.0",
|
||||
"json-stringify-pretty-compact": "^4.0.0",
|
||||
"minimist": "^1.2.8",
|
||||
@@ -894,16 +886,10 @@
|
||||
"gl-style-validate": "dist/gl-style-validate.mjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@maplibre/maplibre-gl-style-spec/node_modules/@mapbox/unitbezier": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-1.0.0.tgz",
|
||||
"integrity": "sha512-fqd515fjBmANKGGsQ286E2Wvj/XvDFpGzwJxq4CI6jMQue6Oy04uCKp+JWKF00xRTmk6cEu1jPJ9p3xqH8YWqQ==",
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/@maplibre/mlt": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@maplibre/mlt/-/mlt-1.1.11.tgz",
|
||||
"integrity": "sha512-dKvjKdITw9d0y3ndGkSqLUEpWCizMtdq8NB06cHohH/JZ2sJoM7dClR9wzJLUWykjbw9RXDFmhjjNBnNW27mzw==",
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@maplibre/mlt/-/mlt-1.2.1.tgz",
|
||||
"integrity": "sha512-5n5dgolE2EYxwCKgx8vlwURCB8A+kyfJJyThlYimjlGgOcOe2Bhw9VxxnnHC91OC9PgHg+nVdgVPTYPkIo62vg==",
|
||||
"license": "(MIT OR Apache-2.0)",
|
||||
"dependencies": {
|
||||
"@mapbox/point-geometry": "^1.1.0"
|
||||
@@ -920,18 +906,6 @@
|
||||
"pbf": "^5.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@maplibre/vt-pbf/node_modules/pbf": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/pbf/-/pbf-5.1.0.tgz",
|
||||
"integrity": "sha512-Wv0yo0+uZepnoNEKsquhar1F18LogB8oeEikIhUXG16udbiXG7JecHGySwoo6kuMgjmbQYzdrTZlO+/K9t8eZg==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"resolve-protobuf-schema": "^2.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"pbf": "bin/pbf"
|
||||
}
|
||||
},
|
||||
"node_modules/@napi-rs/wasm-runtime": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz",
|
||||
@@ -2077,16 +2051,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/expect": {
|
||||
"version": "4.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.8.tgz",
|
||||
"integrity": "sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.11.tgz",
|
||||
"integrity": "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@standard-schema/spec": "^1.1.0",
|
||||
"@types/chai": "^5.2.2",
|
||||
"@vitest/spy": "4.1.8",
|
||||
"@vitest/utils": "4.1.8",
|
||||
"@vitest/spy": "4.1.11",
|
||||
"@vitest/utils": "4.1.11",
|
||||
"chai": "^6.2.2",
|
||||
"tinyrainbow": "^3.1.0"
|
||||
},
|
||||
@@ -2095,13 +2069,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/mocker": {
|
||||
"version": "4.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.8.tgz",
|
||||
"integrity": "sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.11.tgz",
|
||||
"integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/spy": "4.1.8",
|
||||
"@vitest/spy": "4.1.11",
|
||||
"estree-walker": "^3.0.3",
|
||||
"magic-string": "^0.30.21"
|
||||
},
|
||||
@@ -2122,9 +2096,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/pretty-format": {
|
||||
"version": "4.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.8.tgz",
|
||||
"integrity": "sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.11.tgz",
|
||||
"integrity": "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -2135,13 +2109,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/runner": {
|
||||
"version": "4.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.8.tgz",
|
||||
"integrity": "sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.11.tgz",
|
||||
"integrity": "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/utils": "4.1.8",
|
||||
"@vitest/utils": "4.1.11",
|
||||
"pathe": "^2.0.3"
|
||||
},
|
||||
"funding": {
|
||||
@@ -2149,14 +2123,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/snapshot": {
|
||||
"version": "4.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.8.tgz",
|
||||
"integrity": "sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.11.tgz",
|
||||
"integrity": "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/pretty-format": "4.1.8",
|
||||
"@vitest/utils": "4.1.8",
|
||||
"@vitest/pretty-format": "4.1.11",
|
||||
"@vitest/utils": "4.1.11",
|
||||
"magic-string": "^0.30.21",
|
||||
"pathe": "^2.0.3"
|
||||
},
|
||||
@@ -2165,9 +2139,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/spy": {
|
||||
"version": "4.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.8.tgz",
|
||||
"integrity": "sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.11.tgz",
|
||||
"integrity": "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
@@ -2175,13 +2149,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/utils": {
|
||||
"version": "4.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.8.tgz",
|
||||
"integrity": "sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.11.tgz",
|
||||
"integrity": "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/pretty-format": "4.1.8",
|
||||
"@vitest/pretty-format": "4.1.11",
|
||||
"convert-source-map": "^2.0.0",
|
||||
"tinyrainbow": "^3.1.0"
|
||||
},
|
||||
@@ -2285,9 +2259,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/baseline-browser-mapping": {
|
||||
"version": "2.10.35",
|
||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.35.tgz",
|
||||
"integrity": "sha512-honAfLBde0HAFLdNyBEfuuENkF6zR+ozxqxa/2zJKHBe1qzLqyTSeRKpdPEHAP03rlDGyQOPnCSxnVpVqQo9Mg==",
|
||||
"version": "2.11.21",
|
||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.21.tgz",
|
||||
"integrity": "sha512-uh8vpY/1/YyFkunIDFH/12p7/7VdPKA1hejMVEbdkEaWnUz0Hesvx5EbiU6XxjyHZIOju+ZMbQJkRh+es3/spQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
@@ -2298,32 +2272,31 @@
|
||||
}
|
||||
},
|
||||
"node_modules/bidi-js": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz",
|
||||
"integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==",
|
||||
"dev": true,
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.1.0.tgz",
|
||||
"integrity": "sha512-fX1Onk0tdVPC7obPWB5EbJ1z7NVhLq4m2xZLq2YXBkxzMXIGRpNMU88n0EPgWseKl12J7zXs7qrDxPK4sRs2fg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"require-from-string": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "5.0.6",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz",
|
||||
"integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==",
|
||||
"version": "5.0.9",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz",
|
||||
"integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^4.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "18 || 20 || >=22"
|
||||
"node": "20 || >=22"
|
||||
}
|
||||
},
|
||||
"node_modules/browserslist": {
|
||||
"version": "4.28.2",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz",
|
||||
"integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==",
|
||||
"version": "4.28.9",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.9.tgz",
|
||||
"integrity": "sha512-EWazOblFYUvlGZcfGhPUPmYh3nikUxBVb+y9MJun5f3hBi812X+8MSQTujLBtgK3cf51fJWbWfOjyeO954d+Eg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -2341,11 +2314,11 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"baseline-browser-mapping": "^2.10.12",
|
||||
"caniuse-lite": "^1.0.30001782",
|
||||
"electron-to-chromium": "^1.5.328",
|
||||
"node-releases": "^2.0.36",
|
||||
"update-browserslist-db": "^1.2.3"
|
||||
"baseline-browser-mapping": "^2.11.20",
|
||||
"caniuse-lite": "^1.0.30001810",
|
||||
"electron-to-chromium": "^1.5.420",
|
||||
"node-releases": "^2.0.54",
|
||||
"update-browserslist-db": "^1.3.2"
|
||||
},
|
||||
"bin": {
|
||||
"browserslist": "cli.js"
|
||||
@@ -2355,9 +2328,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001797",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001797.tgz",
|
||||
"integrity": "sha512-l8xKG+gwAIExZGl9FrF7KUwuOmk6wbEPC9Xoy/RtnWv1XG0Q4LFlagaLpUv3Kiza3W/wm27zy0yWJEieYKAP6w==",
|
||||
"version": "1.0.30001810",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz",
|
||||
"integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -2523,9 +2496,9 @@
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/earcut": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.2.tgz",
|
||||
"integrity": "sha512-X7hshQbLyMJ/3RPhyObLARM2sNxxmRALLKx1+NVFFnQ9gKzmCrxm9+uLIAdBcvc8FNLpctqlQ2V6AE92Ol9UDQ==",
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/earcut/-/earcut-3.2.3.tgz",
|
||||
"integrity": "sha512-vnS4AVwp1KHAF13i1vp1/2D5evWy3k5u/iW/B81QVsUZtV8cv2tU0b2VNFlqvh4kYwrFMDdjPCfAmfyJW9y14Q==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/echarts": {
|
||||
@@ -2539,9 +2512,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.371",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.371.tgz",
|
||||
"integrity": "sha512-e9htk9mAYL6AzmkEhSvVVw7IWGSBJ/Bqdn2eRyRLrj1g6sncN4WbFt5qnILYoCktktr45pyjIrOiRvBThQ808w==",
|
||||
"version": "1.5.426",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.426.tgz",
|
||||
"integrity": "sha512-2Gcq6inCQs/AqfHP3f5ftCzk+pqeW2VlA1LgmPqEj2hfBO8HiZRspNYkD4HzFBe4u6lGqca4BspFr6Ix4Q400g==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
@@ -3515,27 +3488,26 @@
|
||||
}
|
||||
},
|
||||
"node_modules/maplibre-gl": {
|
||||
"version": "5.24.0",
|
||||
"resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-5.24.0.tgz",
|
||||
"integrity": "sha512-ALyFxgtd5R+65UqZ/++lOqwWcC0SNho9c27fYSyLmG7AfnAul2o46F05aDJGPbFU57wos9dgcIySHs0Xe6ia3A==",
|
||||
"version": "6.9.0",
|
||||
"resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-6.9.0.tgz",
|
||||
"integrity": "sha512-vFMwMK0Zs+NM/rOMSdtu8bO30DIexhBEVi5KC6f70/XtI+L/K2wC3LsDCAXFZ4s8ik5gAuDugfCNbpllpdJ9bA==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"@mapbox/jsonlint-lines-primitives": "^2.0.2",
|
||||
"@mapbox/point-geometry": "^1.1.0",
|
||||
"@mapbox/tiny-sdf": "^2.1.0",
|
||||
"@mapbox/unitbezier": "^0.0.1",
|
||||
"@mapbox/vector-tile": "^2.0.4",
|
||||
"@mapbox/whoots-js": "^3.1.0",
|
||||
"@maplibre/geojson-vt": "^6.1.0",
|
||||
"@maplibre/maplibre-gl-style-spec": "^24.8.1",
|
||||
"@maplibre/mlt": "^1.1.8",
|
||||
"@maplibre/vt-pbf": "^4.3.0",
|
||||
"@mapbox/tiny-sdf": "^2.2.0",
|
||||
"@mapbox/unitbezier": "^1.0.0",
|
||||
"@mapbox/vector-tile": "^3.0.0",
|
||||
"@maplibre/geojson-vt": "^6.1.1",
|
||||
"@maplibre/maplibre-gl-style-spec": "^26.4.2",
|
||||
"@maplibre/mlt": "^1.2.1",
|
||||
"@maplibre/vt-pbf": "^4.3.2",
|
||||
"@types/geojson": "^7946.0.16",
|
||||
"earcut": "^3.0.2",
|
||||
"bidi-js": "^1.1.0",
|
||||
"earcut": "^3.2.3",
|
||||
"gl-matrix": "^3.4.4",
|
||||
"kdbush": "^4.0.2",
|
||||
"kdbush": "^4.1.0",
|
||||
"murmurhash-js": "^1.0.0",
|
||||
"pbf": "^4.0.1",
|
||||
"pbf": "^5.1.2",
|
||||
"potpack": "^2.1.0",
|
||||
"quickselect": "^3.0.0",
|
||||
"tinyqueue": "^3.0.0"
|
||||
@@ -3604,9 +3576,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.12",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
|
||||
"integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
|
||||
"version": "3.3.18",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz",
|
||||
"integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -3630,9 +3602,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-releases": {
|
||||
"version": "2.0.47",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.47.tgz",
|
||||
"integrity": "sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==",
|
||||
"version": "2.0.55",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.55.tgz",
|
||||
"integrity": "sha512-mIrE/Cw9y+9Au6dS5vDKDhQza9YvG6w+ZrS6X+ZzA7yFW/soAeaups4Qzn1bL6g5FVy8WtP79+0j82oPIbqRjQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -3744,9 +3716,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pbf": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/pbf/-/pbf-4.0.2.tgz",
|
||||
"integrity": "sha512-J0ajxARhZfpUEebxYs1vhMGMuLSXtBe1e+fFPDrf2uA2hgo+UshKfNUWOz92HJNz6/NFEXseQPddnHkTreWRqg==",
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/pbf/-/pbf-5.1.2.tgz",
|
||||
"integrity": "sha512-mnvGdvOrIvJOBGUEdGkrVXjN8E/VkIJCkf2eS1DH2yv82ORUlLttmDt0rWY38yYZmVwciZwBUvHM20qxBZf40w==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"resolve-protobuf-schema": "^2.1.0"
|
||||
@@ -3776,9 +3748,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.15",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz",
|
||||
"integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==",
|
||||
"version": "8.5.28",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz",
|
||||
"integrity": "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -3796,7 +3768,7 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.12",
|
||||
"nanoid": "^3.3.18",
|
||||
"picocolors": "^1.1.1",
|
||||
"source-map-js": "^1.2.1"
|
||||
},
|
||||
@@ -3888,9 +3860,9 @@
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/react-router": {
|
||||
"version": "7.17.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.17.0.tgz",
|
||||
"integrity": "sha512-FDELK7rTMlCHO5+reyXsPlmfr7N1F91lPHsWYfMEGQm/KQ+F4JFM8jGoeQDmDvdTs93Fw9aSilH+uKRb4/jXvQ==",
|
||||
"version": "7.18.2",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.18.2.tgz",
|
||||
"integrity": "sha512-aUVMjFm3GAPTTZL7oYr5E7ETiqfQCHRLH+B+5afnICvf0r7kkK4eR6SMuwbSTJw/7t+12khT/Kahij49fqOCIg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cookie": "^1.0.1",
|
||||
@@ -3910,12 +3882,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-router-dom": {
|
||||
"version": "7.17.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.17.0.tgz",
|
||||
"integrity": "sha512-fyU2yjGups/hE6Xz0I5ZYbVL8Gx29eCjgpHaRaTaVU+OOAdfRX05KsvyRm0GO8YQwOkhpU3MurW1jyMUJn+zSw==",
|
||||
"version": "7.18.2",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.18.2.tgz",
|
||||
"integrity": "sha512-AIKJ/jgGlFb3EbfCXk5Gzshiwt+l3mqbCrNjmEWMMjqQxNJ3svBa6bgzFyCC2Sw3RA0VWF1kg3uQf2OFhxb8hw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"react-router": "7.17.0"
|
||||
"react-router": "7.18.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
@@ -3943,7 +3915,6 @@
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
||||
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
@@ -4163,9 +4134,9 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/tinyrainbow": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz",
|
||||
"integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==",
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz",
|
||||
"integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -4289,9 +4260,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/undici": {
|
||||
"version": "7.28.0",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-7.28.0.tgz",
|
||||
"integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==",
|
||||
"version": "7.29.1",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-7.29.1.tgz",
|
||||
"integrity": "sha512-RYONW2MeafgYlkVOKYKkA/Ag7BmXqgIWCa8t1m0JcxrQg9pI9lEqRhAOruOBCbAohOa/gkCF+iPi9hrgvTzu6Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -4306,9 +4277,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/update-browserslist-db": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
|
||||
"integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz",
|
||||
"integrity": "sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -4425,19 +4396,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vitest": {
|
||||
"version": "4.1.8",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.8.tgz",
|
||||
"integrity": "sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.11.tgz",
|
||||
"integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/expect": "4.1.8",
|
||||
"@vitest/mocker": "4.1.8",
|
||||
"@vitest/pretty-format": "4.1.8",
|
||||
"@vitest/runner": "4.1.8",
|
||||
"@vitest/snapshot": "4.1.8",
|
||||
"@vitest/spy": "4.1.8",
|
||||
"@vitest/utils": "4.1.8",
|
||||
"@vitest/expect": "4.1.11",
|
||||
"@vitest/mocker": "4.1.11",
|
||||
"@vitest/pretty-format": "4.1.11",
|
||||
"@vitest/runner": "4.1.11",
|
||||
"@vitest/snapshot": "4.1.11",
|
||||
"@vitest/spy": "4.1.11",
|
||||
"@vitest/utils": "4.1.11",
|
||||
"es-module-lexer": "^2.0.0",
|
||||
"expect-type": "^1.3.0",
|
||||
"magic-string": "^0.30.21",
|
||||
@@ -4465,12 +4436,12 @@
|
||||
"@edge-runtime/vm": "*",
|
||||
"@opentelemetry/api": "^1.9.0",
|
||||
"@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
|
||||
"@vitest/browser-playwright": "4.1.8",
|
||||
"@vitest/browser-preview": "4.1.8",
|
||||
"@vitest/browser-webdriverio": "4.1.8",
|
||||
"@vitest/coverage-istanbul": "4.1.8",
|
||||
"@vitest/coverage-v8": "4.1.8",
|
||||
"@vitest/ui": "4.1.8",
|
||||
"@vitest/browser-playwright": "4.1.11",
|
||||
"@vitest/browser-preview": "4.1.11",
|
||||
"@vitest/browser-webdriverio": "4.1.11",
|
||||
"@vitest/coverage-istanbul": "4.1.11",
|
||||
"@vitest/coverage-v8": "4.1.11",
|
||||
"@vitest/ui": "4.1.11",
|
||||
"happy-dom": "*",
|
||||
"jsdom": "*",
|
||||
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
|
||||
+3
-3
@@ -21,10 +21,10 @@
|
||||
"@tanstack/react-query": "^5.100.11",
|
||||
"@tanstack/react-virtual": "^3.13.25",
|
||||
"echarts": "6.1.0",
|
||||
"maplibre-gl": "^5.24.0",
|
||||
"maplibre-gl": "^6.9.0",
|
||||
"react": "^19.2.6",
|
||||
"react-dom": "^19.2.6",
|
||||
"react-router-dom": "^7.15.1"
|
||||
"react-router-dom": "^7.18.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^10.0.1",
|
||||
@@ -44,6 +44,6 @@
|
||||
"typescript": "~6.0.2",
|
||||
"typescript-eslint": "^8.59.2",
|
||||
"vite": "^8.0.12",
|
||||
"vitest": "^4.1.7"
|
||||
"vitest": "^4.1.11"
|
||||
}
|
||||
}
|
||||
@@ -184,7 +184,7 @@ export function MapView({ wsManager, selectedNodeId, onSelectNode }: MapViewProp
|
||||
}, [iatas, selectedIatas]);
|
||||
const borderData = useMapBordersData(borderIatas, borders);
|
||||
|
||||
const { containerRef, mapRef, isReady, error } = useMapLibre(styleId, fitPoints, handleStyleError, initialCamera);
|
||||
const { containerRef, mapRef, isReady, error, nodeIconResolverRef } = useMapLibre(styleId, fitPoints, handleStyleError, initialCamera);
|
||||
const isDark = resolveMapStyle(styleId).dark; // drives marker theming + maplibre control chrome
|
||||
|
||||
// Snapshot the current view (live camera + settings) into deep-link params for the copy button.
|
||||
@@ -205,7 +205,7 @@ export function MapView({ wsManager, selectedNodeId, onSelectNode }: MapViewProp
|
||||
return { tab: "Map", ...buildMapParams(snapshot) };
|
||||
}, [mapRef, clustered, typeFilter, neighborLines, styleId, packetFlow, borders]);
|
||||
|
||||
useMapNodes(mapRef, isReady, geojson, isDark, themeKey, clustered, onSelectNode, selectedNodeId, packetFlow, focusIds, `${regionKey}:${typeFilter}`);
|
||||
useMapNodes(mapRef, nodeIconResolverRef, isReady, geojson, isDark, themeKey, clustered, onSelectNode, selectedNodeId, packetFlow, focusIds, `${regionKey}:${typeFilter}`);
|
||||
useMapNeighbors(mapRef, isReady, neighborEdges, themeKey);
|
||||
useMapBorders(mapRef, isReady, borderData, themeKey);
|
||||
useMapPacketFlow(mapRef, isReady, packetFlow, wsManager, themeKey, regionKey);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// src/features/map/PacketPathMap.tsx
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import maplibregl from "maplibre-gl";
|
||||
import { Map as MapLibreMap, NavigationControl, AttributionControl, Popup, LngLatBounds } from "maplibre-gl";
|
||||
import "./maplibre-worker";
|
||||
import type {
|
||||
Map as MapLibreMap,
|
||||
GeoJSONSource,
|
||||
LineLayerSpecification,
|
||||
CircleLayerSpecification,
|
||||
@@ -38,7 +38,7 @@ export function PacketPathMap({ paths, selectedKey, styleId }: {
|
||||
// build the map once (styleId is read at creation; the popup doesn't hot-swap basemaps)
|
||||
useEffect(() => {
|
||||
if (mapRef.current || !containerRef.current) return;
|
||||
const map = new maplibregl.Map({
|
||||
const map = new MapLibreMap({
|
||||
container: containerRef.current,
|
||||
style: resolveMapStyle(styleId).url,
|
||||
center: DEFAULT_CENTER,
|
||||
@@ -46,8 +46,8 @@ export function PacketPathMap({ paths, selectedKey, styleId }: {
|
||||
attributionControl: false,
|
||||
});
|
||||
mapRef.current = map;
|
||||
map.addControl(new maplibregl.NavigationControl({ showCompass: false }), "top-right");
|
||||
map.addControl(new maplibregl.AttributionControl({ compact: true }));
|
||||
map.addControl(new NavigationControl({ showCompass: false }), "top-right");
|
||||
map.addControl(new AttributionControl({ compact: true }));
|
||||
// start the attribution as a bare (i) instead of the wide expanded bar it pops open on load —
|
||||
// on mobile that bar overlaps the observer list beneath the map (same trick as useMapLibre)
|
||||
const attrib = map.getContainer().querySelector(".maplibregl-ctrl-attrib");
|
||||
@@ -69,7 +69,7 @@ export function PacketPathMap({ paths, selectedKey, styleId }: {
|
||||
coords.textContent = `${lat.toFixed(5)}, ${lng.toFixed(5)}`;
|
||||
el.append(name, coords);
|
||||
// a fresh popup per click; closeOnClick removes the previous one on the same click
|
||||
new maplibregl.Popup({ closeButton: false, closeOnClick: true, offset: 10 })
|
||||
new Popup({ closeButton: false, closeOnClick: true, offset: 10 })
|
||||
.setLngLat([lng, lat]).setDOMContent(el).addTo(map);
|
||||
});
|
||||
const onLoad = () => setReady(true);
|
||||
@@ -124,7 +124,7 @@ export function PacketPathMap({ paths, selectedKey, styleId }: {
|
||||
(map.getSource(NODE_SOURCE) as GeoJSONSource).setData(points);
|
||||
|
||||
if (bounds.length) {
|
||||
const b = bounds.reduce((acc, p) => acc.extend(p), new maplibregl.LngLatBounds(bounds[0], bounds[0]));
|
||||
const b = bounds.reduce((acc, p) => acc.extend(p), new LngLatBounds(bounds[0], bounds[0]));
|
||||
map.fitBounds(b, { padding: 60, maxZoom: IATA_ZOOM });
|
||||
}
|
||||
}, [ready, paths, selectedKey]);
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import { setWorkerUrl } from "maplibre-gl";
|
||||
import workerUrl from "maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url";
|
||||
|
||||
// maplibre 6 can't find its worker through Vite's module graph on its own; without this the map
|
||||
// silently never fetches vector tiles. Import once from anything that constructs a Map.
|
||||
setWorkerUrl(workerUrl);
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
} from "./types";
|
||||
|
||||
// Marker icons: per-type SVG + cluster hexagon, recolored and rasterized to maplibre images (unknown
|
||||
// type = canvas ring). Async, so provided lazily via styleimagemissing in useMapNodes; re-colors on theme.
|
||||
// type = canvas ring). Async, so provided lazily via the missing-image resolver in useMapNodes; re-colors on theme.
|
||||
|
||||
// Glyph SVGs as raw text per type (+ observer variant). Marker style follows the basemap: filled
|
||||
// Glitch on dark, hollow Wireframe on light — which is exactly what isDark encodes. import.meta.glob
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import maplibregl from "maplibre-gl";
|
||||
import type { Map as MapLibreMap, RasterDEMSourceSpecification } from "maplibre-gl";
|
||||
import { Map as MapLibreMap, NavigationControl, ScaleControl, AttributionControl, LngLatBounds } from "maplibre-gl";
|
||||
import type { RasterDEMSourceSpecification } from "maplibre-gl";
|
||||
import "./maplibre-worker";
|
||||
import {
|
||||
DEM_TILES,
|
||||
DEM_ATTRIBUTION,
|
||||
@@ -78,6 +79,7 @@ export function useMapLibre(
|
||||
const lastGoodStyleIdRef = useRef(styleId); // last style that loaded; the revert target on a failed swap
|
||||
const hasLoadedRef = useRef(false); // a style has loaded at least once (distinguishes initial-load failure)
|
||||
const swapPendingRef = useRef(false); // a setStyle() basemap swap is in flight (awaiting style.load)
|
||||
const nodeIconResolverRef = useRef<((id: string) => Promise<void>) | null>(null); // filled by useMapNodes
|
||||
const onStyleErrorRef = useRef(onStyleError);
|
||||
const lastFitKeyRef = useRef<string | null>(null); // last applied fit target; skips redundant re-fits
|
||||
const skipInitialFitRef = useRef(!!initialCamera); // let a deep-link camera win over the first fit
|
||||
@@ -103,7 +105,7 @@ export function useMapLibre(
|
||||
|
||||
// open at the deep-link camera if one was given, else the default view; the fit effect frames the
|
||||
// selection once the style is ready (unless a deep-link camera suppresses that first fit)
|
||||
const map = new maplibregl.Map({
|
||||
const map = new MapLibreMap({
|
||||
container,
|
||||
style: resolveMapStyle(styleIdRef.current).url,
|
||||
center: initialCameraRef.current?.center ?? DEFAULT_CENTER,
|
||||
@@ -116,9 +118,9 @@ export function useMapLibre(
|
||||
mapRef.current = map;
|
||||
lastStyleIdRef.current = styleIdRef.current;
|
||||
|
||||
map.addControl(new maplibregl.NavigationControl({ visualizePitch: true }), "top-right");
|
||||
map.addControl(new maplibregl.ScaleControl({ unit: "metric" }), "bottom-left");
|
||||
map.addControl(new maplibregl.AttributionControl({ compact: true })); // bottom-right
|
||||
map.addControl(new NavigationControl({ visualizePitch: true }), "top-right");
|
||||
map.addControl(new ScaleControl({ unit: "metric" }), "bottom-left");
|
||||
map.addControl(new AttributionControl({ compact: true })); // bottom-right
|
||||
// maplibre pops the compact attribution open the first time the basemap credit loads (it tacks
|
||||
// on .maplibregl-compact-show). Mark it .maplibregl-compact up front so it skips that and stays
|
||||
// a bare (i) on load — clicking it still opens the credit.
|
||||
@@ -141,14 +143,16 @@ export function useMapLibre(
|
||||
// "circle-11"), so maplibre warns on every load. Hand it a transparent 1x1 for anything that
|
||||
// isn't ours and the noise goes away — a missing icon already draws nothing, so the map looks
|
||||
// identical. Our own markers all start with "node-" and are rasterized by useMapNodes, so we
|
||||
// leave those alone. This lives here (not in useMapNodes) so it's listening before the base
|
||||
// leave those alone. This lives here (not in useMapNodes) so it's installed before the base
|
||||
// style's first paint, when those icons are first requested.
|
||||
map.on("styleimagemissing", (e) => {
|
||||
if (!e.id.startsWith("node-") && !map.hasImage(e.id)) map.addImage(e.id, new ImageData(1, 1));
|
||||
// maplibre allows one resolver per map, so node icons route through a slot useMapNodes fills.
|
||||
map.setMissingStyleImageResolver((id) => {
|
||||
if (id.startsWith("node-")) return nodeIconResolverRef.current?.(id);
|
||||
if (!map.hasImage(id)) map.addImage(id, new ImageData(1, 1));
|
||||
});
|
||||
|
||||
map.on("error", (e) => {
|
||||
const err = e as { error?: Error; sourceId?: string; tile?: unknown };
|
||||
const err = e as unknown as { error?: Error; sourceId?: string; tile?: unknown };
|
||||
// A single tile/source failure (one basemap or DEM tile timing out / 403 / a momentary network
|
||||
// blip) is transient and non-fatal — the rest of the map stays usable — so never blank the map
|
||||
// for it. maplibre tags tile/source errors with a tile/sourceId; style-level errors have neither.
|
||||
@@ -212,7 +216,7 @@ export function useMapLibre(
|
||||
|
||||
const bounds = fitPoints.reduce(
|
||||
(b, p) => b.extend(p),
|
||||
new maplibregl.LngLatBounds(fitPoints[0], fitPoints[0]),
|
||||
new LngLatBounds(fitPoints[0], fitPoints[0]),
|
||||
);
|
||||
map.fitBounds(bounds, {
|
||||
padding: 48,
|
||||
@@ -222,5 +226,5 @@ export function useMapLibre(
|
||||
});
|
||||
}, [fitPoints, isReady]);
|
||||
|
||||
return { containerRef, mapRef, isReady, error };
|
||||
return { containerRef, mapRef, isReady, error, nodeIconResolverRef };
|
||||
}
|
||||
@@ -98,6 +98,7 @@ const SPIDER_LEAVES_LAYOUT: SymbolLayerSpecification["layout"] = {
|
||||
// labels at high zoom). Like useMapLibre, the imperative work re-adds itself after every style switch.
|
||||
export function useMapNodes(
|
||||
mapRef: React.RefObject<MapLibreMap | null>,
|
||||
nodeIconResolverRef: React.RefObject<((id: string) => Promise<void>) | null>,
|
||||
isReady: boolean,
|
||||
geojson: NodeFC,
|
||||
isDark: boolean,
|
||||
@@ -281,8 +282,9 @@ export function useMapNodes(
|
||||
}, [mapRef, isReady, isDark, clustered, themeKey]);
|
||||
|
||||
// Supply and re-color the marker images. SVG glyphs rasterize async, so they're provided both
|
||||
// proactively here and lazily on styleimagemissing. Re-runs on a theme/basemap/DPR change to
|
||||
// re-rasterize; a basemap switch also drops the images via setStyle, which this then restores.
|
||||
// proactively here and lazily through the map's missing-image resolver. Re-runs on a theme/
|
||||
// basemap/DPR change to re-rasterize; a basemap switch also drops the images via setStyle, which
|
||||
// this then restores.
|
||||
useEffect(() => {
|
||||
const map = mapRef.current;
|
||||
if (!map || !isReady) return;
|
||||
@@ -297,12 +299,11 @@ export function useMapNodes(
|
||||
.catch(() => {
|
||||
/* an icon failed to rasterize; the layer simply draws nothing for that id */
|
||||
});
|
||||
const onMissing = (e: { id: string }) => provide(e.id);
|
||||
map.on("styleimagemissing", onMissing);
|
||||
nodeIconResolverRef.current = provide;
|
||||
// A symbol won't draw until its icon is in, and adding one late doesn't redraw tiles that
|
||||
// already laid out — that's the "markers only show after I pan/zoom" bug. So once every icon
|
||||
// is ready, nudge the source to lay the markers out again (setData reloads the whole source).
|
||||
// styleimagemissing still covers anything asked for before we get here.
|
||||
// The resolver still covers anything asked for before we get here.
|
||||
Promise.all(MAP_ICON_IDS.map(provide)).then(() => {
|
||||
if (cancelled || mapRef.current !== map) return;
|
||||
const src = map.getSource(NODES_SOURCE_ID) as GeoJSONSource | undefined;
|
||||
@@ -310,9 +311,9 @@ export function useMapNodes(
|
||||
});
|
||||
return () => {
|
||||
cancelled = true;
|
||||
map.off("styleimagemissing", onMissing);
|
||||
nodeIconResolverRef.current = null;
|
||||
};
|
||||
}, [mapRef, isReady, isDark, themeKey, dpr]);
|
||||
}, [mapRef, nodeIconResolverRef, isReady, isDark, themeKey, dpr]);
|
||||
|
||||
// Reflect the shared selection as a ring (mirrors the table's row highlight). Its own effect so
|
||||
// changing the selection doesn't rebuild the source/layers.
|
||||
|
||||
Reference in new issue
Block a user