mirror of
https://github.com/Flomp/wanderer.git
synced 2026-01-10 15:10:21 -06:00
starts transition to maplibre
This commit is contained in:
Generated
+366
-6
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "wanderer",
|
||||
"version": "0.10.1",
|
||||
"version": "0.11.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "wanderer",
|
||||
"version": "0.10.1",
|
||||
"version": "0.11.0",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^6.5.1",
|
||||
"@sveltejs/adapter-node": "^4.0.1",
|
||||
@@ -18,6 +18,8 @@
|
||||
"@types/xmldom": "^0.1.34",
|
||||
"canvg": "^4.0.1",
|
||||
"chart.js": "^4.4.6",
|
||||
"chartjs-plugin-crosshair": "^2.0.0",
|
||||
"chartjs-plugin-zoom": "^2.1.0",
|
||||
"crypto-random-string": "^5.0.0",
|
||||
"heic2any": "^0.0.4",
|
||||
"instead": "^1.0.3",
|
||||
@@ -27,6 +29,7 @@
|
||||
"leaflet": "^1.9.4",
|
||||
"leaflet-gpx": "^1.7.0",
|
||||
"leaflet.awesome-markers": "^2.0.5",
|
||||
"maplibre-gl": "^4.7.1",
|
||||
"meilisearch": "^0.37.0",
|
||||
"nouislider": "^15.7.1",
|
||||
"pdfkit": "^0.15.0",
|
||||
@@ -568,6 +571,92 @@
|
||||
"resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz",
|
||||
"integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw=="
|
||||
},
|
||||
"node_modules/@mapbox/geojson-rewind": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/geojson-rewind/-/geojson-rewind-0.5.2.tgz",
|
||||
"integrity": "sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==",
|
||||
"dependencies": {
|
||||
"get-stream": "^6.0.1",
|
||||
"minimist": "^1.2.6"
|
||||
},
|
||||
"bin": {
|
||||
"geojson-rewind": "geojson-rewind"
|
||||
}
|
||||
},
|
||||
"node_modules/@mapbox/geojson-rewind/node_modules/get-stream": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
|
||||
"integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@mapbox/point-geometry": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz",
|
||||
"integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ=="
|
||||
},
|
||||
"node_modules/@mapbox/tiny-sdf": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.0.6.tgz",
|
||||
"integrity": "sha512-qMqa27TLw+ZQz5Jk+RcwZGH7BQf5G/TrutJhspsca/3SHwmgKQ1iq+d3Jxz5oysPVYTGP6aXxCo5Lk9Er6YBAA=="
|
||||
},
|
||||
"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=="
|
||||
},
|
||||
"node_modules/@mapbox/vector-tile": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-1.3.1.tgz",
|
||||
"integrity": "sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==",
|
||||
"dependencies": {
|
||||
"@mapbox/point-geometry": "~0.1.0"
|
||||
}
|
||||
},
|
||||
"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==",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@maplibre/maplibre-gl-style-spec": {
|
||||
"version": "20.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-20.4.0.tgz",
|
||||
"integrity": "sha512-AzBy3095fTFPjDjmWpR2w6HVRAZJ6hQZUCwk5Plz6EyfnfuQW1odeW5i2Ai47Y6TBA2hQnC+azscjBSALpaWgw==",
|
||||
"dependencies": {
|
||||
"@mapbox/jsonlint-lines-primitives": "~2.0.2",
|
||||
"@mapbox/unitbezier": "^0.0.1",
|
||||
"json-stringify-pretty-compact": "^4.0.0",
|
||||
"minimist": "^1.2.8",
|
||||
"quickselect": "^2.0.0",
|
||||
"rw": "^1.3.3",
|
||||
"tinyqueue": "^3.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"gl-style-format": "dist/gl-style-format.mjs",
|
||||
"gl-style-migrate": "dist/gl-style-migrate.mjs",
|
||||
"gl-style-validate": "dist/gl-style-validate.mjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@maplibre/maplibre-gl-style-spec/node_modules/quickselect": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz",
|
||||
"integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw=="
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
@@ -1089,9 +1178,22 @@
|
||||
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw=="
|
||||
},
|
||||
"node_modules/@types/geojson": {
|
||||
"version": "7946.0.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.13.tgz",
|
||||
"integrity": "sha512-bmrNrgKMOhM3WsafmbGmC+6dsF2Z308vLFsQ3a/bT8X8Sv5clVYpPars/UPq+sAaJP+5OoLAYgwbkS5QEJdLUQ=="
|
||||
"version": "7946.0.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz",
|
||||
"integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg=="
|
||||
},
|
||||
"node_modules/@types/geojson-vt": {
|
||||
"version": "3.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/geojson-vt/-/geojson-vt-3.2.5.tgz",
|
||||
"integrity": "sha512-qDO7wqtprzlpe8FfQ//ClPV9xiuoh2nkIgiouIptON9w5jvD/fA4szvP9GBlDVdJ5dldAl0kX/sy3URbWwLx0g==",
|
||||
"dependencies": {
|
||||
"@types/geojson": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/hammerjs": {
|
||||
"version": "2.0.46",
|
||||
"resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.46.tgz",
|
||||
"integrity": "sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw=="
|
||||
},
|
||||
"node_modules/@types/leaflet": {
|
||||
"version": "1.9.8",
|
||||
@@ -1118,6 +1220,21 @@
|
||||
"@types/leaflet": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/mapbox__point-geometry": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/mapbox__point-geometry/-/mapbox__point-geometry-0.1.4.tgz",
|
||||
"integrity": "sha512-mUWlSxAmYLfwnRBmgYV86tgYmMIICX4kza8YnE/eIlywGe2XoOxlpVnXWwir92xRLjwyarqwpu2EJKD2pk0IUA=="
|
||||
},
|
||||
"node_modules/@types/mapbox__vector-tile": {
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/mapbox__vector-tile/-/mapbox__vector-tile-1.3.4.tgz",
|
||||
"integrity": "sha512-bpd8dRn9pr6xKvuEBQup8pwQfD4VUyqO/2deGjfpe6AwC8YRlyEipvefyRJUSiCJTZuCb8Pl1ciVV5ekqJ96Bg==",
|
||||
"dependencies": {
|
||||
"@types/geojson": "*",
|
||||
"@types/mapbox__point-geometry": "*",
|
||||
"@types/pbf": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.11.25",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.25.tgz",
|
||||
@@ -1131,6 +1248,11 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz",
|
||||
"integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A=="
|
||||
},
|
||||
"node_modules/@types/pbf": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/pbf/-/pbf-3.0.5.tgz",
|
||||
"integrity": "sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA=="
|
||||
},
|
||||
"node_modules/@types/pug": {
|
||||
"version": "2.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.10.tgz",
|
||||
@@ -1152,6 +1274,14 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.3.tgz",
|
||||
"integrity": "sha512-pXNfAD3KHOdif9EQXZ9deK82HVNaXP5ZIF5RP2QG6OQFNTaY2YIetfrE9t528vEreGQvEPRDDc8muaoYeK0SxQ=="
|
||||
},
|
||||
"node_modules/@types/supercluster": {
|
||||
"version": "7.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/supercluster/-/supercluster-7.1.3.tgz",
|
||||
"integrity": "sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA==",
|
||||
"dependencies": {
|
||||
"@types/geojson": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/three": {
|
||||
"version": "0.161.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.161.2.tgz",
|
||||
@@ -1704,6 +1834,26 @@
|
||||
"pnpm": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/chartjs-plugin-crosshair": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chartjs-plugin-crosshair/-/chartjs-plugin-crosshair-2.0.0.tgz",
|
||||
"integrity": "sha512-Vs6strRvYpzL92v40r/rAWhh+7au8VnfyC/m2ZHXcXeLEWeFjDgMvXjWdX+eARhbgHQo+uGIKyq9fmkS79GIyQ==",
|
||||
"peerDependencies": {
|
||||
"chart.js": "^4.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/chartjs-plugin-zoom": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/chartjs-plugin-zoom/-/chartjs-plugin-zoom-2.1.0.tgz",
|
||||
"integrity": "sha512-7lMimfQCUaIJLhPJaWSAA4gw+1m8lyR3Wn+M3MxjHbM/XxRUnOxN7cM5RR9jUmxmyW0h7L2hZ8KhvUsqrFxy/Q==",
|
||||
"dependencies": {
|
||||
"@types/hammerjs": "^2.0.45",
|
||||
"hammerjs": "^2.0.8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"chart.js": ">=3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/check-error": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz",
|
||||
@@ -2263,6 +2413,11 @@
|
||||
"integrity": "sha512-5RXhAXSCrKTqt9pSbobT9PVRX+oPpENplTZqCiK1l0ya+ZOzwo9kqsGLbYRsAhzIiLCwKEy99XKSSrqnRTLVcw==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/earcut": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.0.tgz",
|
||||
"integrity": "sha512-41Fs7Q/PLq1SDbqjsgcY7GA42T0jvaCNGXgGtsNdvg+Yv8eIu06bxv4/PoREkZ9nMDNwnUSG9OFB9+yv8eKhDg=="
|
||||
},
|
||||
"node_modules/eastasianwidth": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
||||
@@ -2669,6 +2824,11 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/geojson-vt": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-4.0.2.tgz",
|
||||
"integrity": "sha512-AV9ROqlNqoZEIJGfm1ncNjEXfkz2hdFlZf0qkVfmkwdKa8vj7H16YUOT81rJw1rdFhyEDlN2Tds91p/glzbl5A=="
|
||||
},
|
||||
"node_modules/get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
@@ -2716,6 +2876,11 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/gl-matrix": {
|
||||
"version": "3.4.3",
|
||||
"resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz",
|
||||
"integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA=="
|
||||
},
|
||||
"node_modules/glob": {
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||
@@ -2748,6 +2913,41 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/global-prefix": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-4.0.0.tgz",
|
||||
"integrity": "sha512-w0Uf9Y9/nyHinEk5vMJKRie+wa4kR5hmDbEhGGds/kG1PwGLLHKRoNMeJOyCQjjBkANlnScqgzcFwGHgmgLkVA==",
|
||||
"dependencies": {
|
||||
"ini": "^4.1.3",
|
||||
"kind-of": "^6.0.3",
|
||||
"which": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/global-prefix/node_modules/isexe": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz",
|
||||
"integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/global-prefix/node_modules/which": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz",
|
||||
"integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==",
|
||||
"dependencies": {
|
||||
"isexe": "^3.1.1"
|
||||
},
|
||||
"bin": {
|
||||
"node-which": "bin/which.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.13.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/globalyzer": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz",
|
||||
@@ -2775,6 +2975,14 @@
|
||||
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/hammerjs": {
|
||||
"version": "2.0.8",
|
||||
"resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz",
|
||||
"integrity": "sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/has-bigints": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
|
||||
@@ -2926,6 +3134,25 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/immediate": {
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
|
||||
@@ -2970,6 +3197,14 @@
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"node_modules/ini": {
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz",
|
||||
"integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==",
|
||||
"engines": {
|
||||
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/instead": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/instead/-/instead-1.0.3.tgz",
|
||||
@@ -3457,6 +3692,11 @@
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/json-stringify-pretty-compact": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-4.0.0.tgz",
|
||||
"integrity": "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q=="
|
||||
},
|
||||
"node_modules/jsonc-parser": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz",
|
||||
@@ -3526,6 +3766,19 @@
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
|
||||
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
|
||||
},
|
||||
"node_modules/kdbush": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz",
|
||||
"integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA=="
|
||||
},
|
||||
"node_modules/kind-of": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
|
||||
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/kleur": {
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
|
||||
@@ -3658,6 +3911,46 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/maplibre-gl": {
|
||||
"version": "4.7.1",
|
||||
"resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-4.7.1.tgz",
|
||||
"integrity": "sha512-lgL7XpIwsgICiL82ITplfS7IGwrB1OJIw/pCvprDp2dhmSSEBgmPzYRvwYYYvJGJD7fxUv1Tvpih4nZ6VrLuaA==",
|
||||
"dependencies": {
|
||||
"@mapbox/geojson-rewind": "^0.5.2",
|
||||
"@mapbox/jsonlint-lines-primitives": "^2.0.2",
|
||||
"@mapbox/point-geometry": "^0.1.0",
|
||||
"@mapbox/tiny-sdf": "^2.0.6",
|
||||
"@mapbox/unitbezier": "^0.0.1",
|
||||
"@mapbox/vector-tile": "^1.3.1",
|
||||
"@mapbox/whoots-js": "^3.1.0",
|
||||
"@maplibre/maplibre-gl-style-spec": "^20.3.1",
|
||||
"@types/geojson": "^7946.0.14",
|
||||
"@types/geojson-vt": "3.2.5",
|
||||
"@types/mapbox__point-geometry": "^0.1.4",
|
||||
"@types/mapbox__vector-tile": "^1.3.4",
|
||||
"@types/pbf": "^3.0.5",
|
||||
"@types/supercluster": "^7.1.3",
|
||||
"earcut": "^3.0.0",
|
||||
"geojson-vt": "^4.0.2",
|
||||
"gl-matrix": "^3.4.3",
|
||||
"global-prefix": "^4.0.0",
|
||||
"kdbush": "^4.0.2",
|
||||
"murmurhash-js": "^1.0.0",
|
||||
"pbf": "^3.3.0",
|
||||
"potpack": "^2.0.0",
|
||||
"quickselect": "^3.0.0",
|
||||
"supercluster": "^8.0.1",
|
||||
"tinyqueue": "^3.0.0",
|
||||
"vt-pbf": "^3.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.14.0",
|
||||
"npm": ">=8.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/maplibre/maplibre-gl-js?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/mdn-data": {
|
||||
"version": "2.0.30",
|
||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
|
||||
@@ -3781,7 +4074,6 @@
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
@@ -3853,6 +4145,11 @@
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"node_modules/murmurhash-js": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/murmurhash-js/-/murmurhash-js-1.0.0.tgz",
|
||||
"integrity": "sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw=="
|
||||
},
|
||||
"node_modules/mz": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
|
||||
@@ -4199,6 +4496,18 @@
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/pbf": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/pbf/-/pbf-3.3.0.tgz",
|
||||
"integrity": "sha512-XDF38WCH3z5OV/OVa8GKUNtLAyneuzbCisx7QUCF8Q6Nutx0WnJrQe5O+kOtBlLfRNUws98Y58Lblp+NJG5T4Q==",
|
||||
"dependencies": {
|
||||
"ieee754": "^1.1.12",
|
||||
"resolve-protobuf-schema": "^2.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"pbf": "bin/pbf"
|
||||
}
|
||||
},
|
||||
"node_modules/pdfkit": {
|
||||
"version": "0.15.0",
|
||||
"resolved": "https://registry.npmjs.org/pdfkit/-/pdfkit-0.15.0.tgz",
|
||||
@@ -4480,6 +4789,11 @@
|
||||
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/potpack": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/potpack/-/potpack-2.0.0.tgz",
|
||||
"integrity": "sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw=="
|
||||
},
|
||||
"node_modules/pretty-format": {
|
||||
"version": "29.7.0",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
|
||||
@@ -4504,6 +4818,11 @@
|
||||
"resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz",
|
||||
"integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA=="
|
||||
},
|
||||
"node_modules/protocol-buffers-schema": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz",
|
||||
"integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw=="
|
||||
},
|
||||
"node_modules/psl": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
|
||||
@@ -4568,6 +4887,11 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/quickselect": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz",
|
||||
"integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g=="
|
||||
},
|
||||
"node_modules/raf": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
|
||||
@@ -4698,6 +5022,14 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve-protobuf-schema": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz",
|
||||
"integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==",
|
||||
"dependencies": {
|
||||
"protocol-buffers-schema": "^3.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/restructure": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/restructure/-/restructure-2.0.1.tgz",
|
||||
@@ -4795,6 +5127,11 @@
|
||||
"queue-microtask": "^1.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/rw": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz",
|
||||
"integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ=="
|
||||
},
|
||||
"node_modules/sade": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz",
|
||||
@@ -5226,6 +5563,14 @@
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/supercluster": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/supercluster/-/supercluster-8.0.1.tgz",
|
||||
"integrity": "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==",
|
||||
"dependencies": {
|
||||
"kdbush": "^4.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/supports-preserve-symlinks-flag": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
||||
@@ -5545,6 +5890,11 @@
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tinyqueue": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz",
|
||||
"integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g=="
|
||||
},
|
||||
"node_modules/tinyspy": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.0.tgz",
|
||||
@@ -5941,6 +6291,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/vt-pbf": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/vt-pbf/-/vt-pbf-3.1.3.tgz",
|
||||
"integrity": "sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==",
|
||||
"dependencies": {
|
||||
"@mapbox/point-geometry": "0.1.0",
|
||||
"@mapbox/vector-tile": "^1.3.1",
|
||||
"pbf": "^3.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/w3c-xmlserializer": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
|
||||
|
||||
@@ -42,6 +42,8 @@
|
||||
"@types/xmldom": "^0.1.34",
|
||||
"canvg": "^4.0.1",
|
||||
"chart.js": "^4.4.6",
|
||||
"chartjs-plugin-crosshair": "^2.0.0",
|
||||
"chartjs-plugin-zoom": "^2.1.0",
|
||||
"crypto-random-string": "^5.0.0",
|
||||
"heic2any": "^0.0.4",
|
||||
"instead": "^1.0.3",
|
||||
@@ -51,6 +53,7 @@
|
||||
"leaflet": "^1.9.4",
|
||||
"leaflet-gpx": "^1.7.0",
|
||||
"leaflet.awesome-markers": "^2.0.5",
|
||||
"maplibre-gl": "^4.7.1",
|
||||
"meilisearch": "^0.37.0",
|
||||
"nouislider": "^15.7.1",
|
||||
"pdfkit": "^0.15.0",
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
--secondary-hover: 243, 244, 246;
|
||||
|
||||
--background: 255, 255, 255;
|
||||
--background-inverse: 7, 10, 36;
|
||||
|
||||
--content: 0, 0, 0;
|
||||
--content-inverse: 255, 255, 255;
|
||||
|
||||
--input-background: 249, 250, 251;
|
||||
--input-background-error: 254, 242, 242;
|
||||
@@ -30,7 +33,10 @@
|
||||
--secondary-hover: 36, 39, 52;
|
||||
|
||||
--background: 7, 10, 36;
|
||||
--background-inverse: 255, 255, 255;
|
||||
|
||||
--content: 255, 255, 255;
|
||||
--content-inverse: 0, 0, 0;
|
||||
|
||||
--input-background: 36, 39, 52;
|
||||
--input-background-error: 69, 10, 10;
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
|
||||
import type { Trail } from "$lib/models/trail";
|
||||
import { gpx2trail } from "$lib/util/gpx_util";
|
||||
import type { Map } from "leaflet";
|
||||
import * as M from "maplibre-gl";
|
||||
import { _ } from "svelte-i18n";
|
||||
import MapWithElevation from "../trail/map_with_elevation.svelte";
|
||||
import MapWithElevationMaplibre from "../trail/map_with_elevation_maplibre.svelte";
|
||||
|
||||
export let summitLogs: SummitLog[] = [];
|
||||
export let showCategory: boolean = false;
|
||||
@@ -22,7 +22,7 @@
|
||||
let openTextModal: () => void;
|
||||
let closeTextModal: () => void;
|
||||
|
||||
let map: Map;
|
||||
let map: M.Map;
|
||||
|
||||
let trail: Trail | null = null;
|
||||
|
||||
@@ -40,8 +40,6 @@
|
||||
|
||||
openMapModal();
|
||||
await tick();
|
||||
|
||||
map.invalidateSize();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -103,7 +101,10 @@
|
||||
bind:closeModal={closeMapModal}
|
||||
>
|
||||
<div slot="content" id="summit-log-table-map" class="h-[32rem]">
|
||||
<MapWithElevation {trail} bind:map></MapWithElevation>
|
||||
{#if trail}
|
||||
<MapWithElevationMaplibre {trail} bind:map
|
||||
></MapWithElevationMaplibre>
|
||||
{/if}
|
||||
</div>
|
||||
</Modal>
|
||||
<Modal
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
<script lang="ts">
|
||||
import { page } from "$app/stores";
|
||||
import type { Trail } from "$lib/models/trail";
|
||||
import { theme } from "$lib/stores/theme_store";
|
||||
import { findStartAndEndPoints } from "$lib/util/geojson_util";
|
||||
import { toGeoJson } from "$lib/util/gpx_util";
|
||||
import {
|
||||
createMarkerFromWaypoint,
|
||||
FontawesomeMarker,
|
||||
} from "$lib/util/maplibre_util";
|
||||
import type { ElevationProfileControl } from "$lib/vendor/maplibre-elevation-profile/elevationprofile-control";
|
||||
import type { GeoJsonObject } from "geojson";
|
||||
import * as M from "maplibre-gl";
|
||||
import "maplibre-gl/dist/maplibre-gl.css";
|
||||
import { onDestroy, onMount } from "svelte";
|
||||
|
||||
export let trail: Trail;
|
||||
export let markers: M.Marker[] = [];
|
||||
export let map: M.Map | null = null;
|
||||
export let crosshairCursor: boolean = false;
|
||||
|
||||
let mapContainer: HTMLDivElement;
|
||||
|
||||
let epc: ElevationProfileControl;
|
||||
|
||||
$: data = toGeoJson(trail.expand.gpx_data!) as GeoJsonObject;
|
||||
|
||||
$: if ($theme == "dark") {
|
||||
epc?.toggleTheme({
|
||||
profileBackgroundColor: "#191b24",
|
||||
elevationGridColor: "#ddd2",
|
||||
labelColor: "#ddd8",
|
||||
crosshairColor: "#fff5",
|
||||
});
|
||||
} else {
|
||||
epc?.toggleTheme({
|
||||
profileBackgroundColor: "#242734",
|
||||
elevationGridColor: "#0002",
|
||||
labelColor: "#0009",
|
||||
crosshairColor: "#0005",
|
||||
});
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
const initialState = {
|
||||
lng: 0,
|
||||
lat: 0,
|
||||
zoom: 14,
|
||||
};
|
||||
const ElevationProfileControl = (
|
||||
await import(
|
||||
"$lib/vendor/maplibre-elevation-profile/elevationprofile-control"
|
||||
)
|
||||
).ElevationProfileControl;
|
||||
|
||||
map = new M.Map({
|
||||
container: mapContainer,
|
||||
style: `https://basemaps.cartocdn.com/gl/positron-gl-style/style.json`,
|
||||
center: [initialState.lng, initialState.lat],
|
||||
zoom: initialState.zoom,
|
||||
});
|
||||
|
||||
for (const waypoint of trail?.expand.waypoints ?? []) {
|
||||
const marker = createMarkerFromWaypoint(waypoint);
|
||||
marker.addTo(map);
|
||||
markers.push(marker);
|
||||
}
|
||||
|
||||
const startEndPoint = findStartAndEndPoints(data);
|
||||
|
||||
const startMarker = new FontawesomeMarker(
|
||||
{ icon: "fa fa-bullseye" },
|
||||
{},
|
||||
)
|
||||
.setLngLat(startEndPoint[0] as M.LngLatLike)
|
||||
.addTo(map);
|
||||
|
||||
const endMarker = new FontawesomeMarker(
|
||||
{ icon: "fa fa-flag-checkered" },
|
||||
{},
|
||||
)
|
||||
.setLngLat(startEndPoint[1] as M.LngLatLike)
|
||||
.addTo(map);
|
||||
|
||||
const elevationMarker = new FontawesomeMarker(
|
||||
{
|
||||
icon: "fa-regular fa-circle",
|
||||
fontSize: "xs",
|
||||
width: 4,
|
||||
backgroundColor: "primary",
|
||||
fontColor: "white",
|
||||
},
|
||||
{},
|
||||
);
|
||||
elevationMarker.setLngLat([0, 0]).addTo(map);
|
||||
elevationMarker.setOpacity("0");
|
||||
|
||||
epc = new ElevationProfileControl({
|
||||
visible: true,
|
||||
profileBackgroundColor: $theme == "light" ? "#242734" : "#191b24",
|
||||
backgroundColor: "bg-menu-background/90",
|
||||
unit: $page.data.settings?.unit ?? "metric",
|
||||
profileLineWidth: 3,
|
||||
displayDistanceGrid: true,
|
||||
tooltipDisplayDPlus: false,
|
||||
onEnter: () => {
|
||||
elevationMarker.setOpacity("1");
|
||||
},
|
||||
onLeave: () => {
|
||||
elevationMarker.setOpacity("0");
|
||||
},
|
||||
onMove: (data) => {
|
||||
elevationMarker.setLngLat(data.position as M.LngLatLike);
|
||||
},
|
||||
});
|
||||
map.addControl(new M.NavigationControl());
|
||||
map.addControl(
|
||||
new M.ScaleControl({
|
||||
maxWidth: 120,
|
||||
unit: $page.data.settings?.unit ?? "metric",
|
||||
}),
|
||||
"top-left",
|
||||
);
|
||||
map.addControl(epc);
|
||||
epc.setData(data, trail.expand.waypoints);
|
||||
|
||||
map.on("load", () => {
|
||||
map!.addSource("trail-source", {
|
||||
type: "geojson",
|
||||
data: data as any,
|
||||
});
|
||||
|
||||
map!.addLayer({
|
||||
id: "uploaded-polygons",
|
||||
type: "line",
|
||||
source: "trail-source",
|
||||
paint: {
|
||||
"line-color": "#648ad5",
|
||||
"line-width": 5,
|
||||
},
|
||||
});
|
||||
map!.fitBounds(data.bbox as any, {
|
||||
animate: false,
|
||||
padding: {
|
||||
top: 16,
|
||||
left: 16,
|
||||
right: 16,
|
||||
bottom: map!.getContainer().clientHeight * 0.3 + 16,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
map?.remove();
|
||||
});
|
||||
</script>
|
||||
|
||||
<div id="map" class:cursor-pointer={crosshairCursor} bind:this={mapContainer}></div>
|
||||
|
||||
<style>
|
||||
#map {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -39,10 +39,11 @@
|
||||
import ShareInfo from "../share_info.svelte";
|
||||
import SummitLogTable from "../summit_log/summit_log_table.svelte";
|
||||
import { pb } from "$lib/pocketbase";
|
||||
import * as M from "maplibre-gl";
|
||||
|
||||
export let trail: Trail;
|
||||
export let mode: "overview" | "map" | "list" = "map";
|
||||
export let markers: Marker[] = [];
|
||||
export let markers: (Marker | M.Marker)[] = [];
|
||||
|
||||
const tabs = [
|
||||
$_("description"),
|
||||
@@ -118,11 +119,19 @@
|
||||
});
|
||||
|
||||
function openMarkerPopup(i: number) {
|
||||
markers[i].openPopup();
|
||||
if (typeof (markers[i] as Marker<any>).openPopup === "function") {
|
||||
(markers[i] as Marker<any>).openPopup();
|
||||
} else {
|
||||
(markers[i] as M.Marker).togglePopup();
|
||||
}
|
||||
}
|
||||
|
||||
function closeMarkerPopup(i: number) {
|
||||
markers[i].closePopup();
|
||||
if (typeof (markers[i] as Marker<any>).closePopup === "function") {
|
||||
(markers[i] as Marker<any>).closePopup();
|
||||
} else {
|
||||
(markers[i] as M.Marker).togglePopup();
|
||||
}
|
||||
}
|
||||
|
||||
async function toggleMapFullScreen() {
|
||||
@@ -239,7 +248,11 @@
|
||||
`https://api.dicebear.com/7.x/initials/svg?seed=${trail.expand.author.username}&backgroundType=gradientLinear`}
|
||||
alt="avatar"
|
||||
/>
|
||||
<a class="underline" href="/profile/{trail.expand.author.id}">{trail.expand.author.username}</a>
|
||||
<a
|
||||
class="underline"
|
||||
href="/profile/{trail.expand.author.id}"
|
||||
>{trail.expand.author.username}</a
|
||||
>
|
||||
</p>
|
||||
{/if}
|
||||
<div class="flex flex-wrap gap-x-8 gap-y-2 mt-4 mr-8">
|
||||
@@ -358,7 +371,9 @@
|
||||
{/if}
|
||||
{#if activeTab == 3}
|
||||
<div class="overflow-x-auto">
|
||||
<SummitLogTable summitLogs={trail.expand.summit_logs} showAuthor
|
||||
<SummitLogTable
|
||||
summitLogs={trail.expand.summit_logs}
|
||||
showAuthor
|
||||
></SummitLogTable>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as xml2js from 'isomorphic-xml2js';
|
||||
import Metadata from './metadata';
|
||||
import Route from './route';
|
||||
import Track from './track';
|
||||
import { allDatesToISOString, calculateDistance, removeEmpty } from './utils';
|
||||
import { allDatesToISOString, haversineDistance, removeEmpty } from './utils';
|
||||
import Waypoint from './waypoint';
|
||||
|
||||
const defaultAttributes = {
|
||||
@@ -104,7 +104,7 @@ export default class GPX {
|
||||
totalElevationLoss += Math.abs(elevationDiff)
|
||||
}
|
||||
|
||||
const distance = calculateDistance(
|
||||
const distance = haversineDistance(
|
||||
prevPoint.$.lat ?? 0,
|
||||
prevPoint.$.lon ?? 0,
|
||||
point.$.lat ?? 0,
|
||||
|
||||
@@ -20,7 +20,7 @@ function allDatesToISOString(obj: Record<string, any>) {
|
||||
});
|
||||
}
|
||||
|
||||
function calculateDistance(lat1: number, lon1: number, lat2: number, lon2: number): number {
|
||||
function haversineDistance(lat1: number, lon1: number, lat2: number, lon2: number): number {
|
||||
const R = 6371; // Radius of the Earth in km
|
||||
const dLat = (lat2 - lat1) * (Math.PI / 180); // Convert degrees to radians
|
||||
const dLon = (lon2 - lon1) * (Math.PI / 180);
|
||||
@@ -33,4 +33,4 @@ function calculateDistance(lat1: number, lon1: number, lat2: number, lon2: numbe
|
||||
return distance;
|
||||
}
|
||||
|
||||
export { removeEmpty, allDatesToISOString, calculateDistance };
|
||||
export { removeEmpty, allDatesToISOString, haversineDistance };
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { page } from "$app/stores";
|
||||
import { currentUser } from "$lib/stores/user_store";
|
||||
import { get } from "svelte/store";
|
||||
|
||||
export function formatTimeHHMM(minutes?: number) {
|
||||
|
||||
@@ -0,0 +1,216 @@
|
||||
import type { BBox, Feature, FeatureCollection, GeoJSON, GeoJsonObject, GeometryCollection, Position } from "geojson";
|
||||
|
||||
export function bbox(
|
||||
geojson: GeoJSON,
|
||||
): BBox {
|
||||
if (geojson.bbox != null) {
|
||||
return geojson.bbox;
|
||||
}
|
||||
const result: BBox = [Infinity, Infinity, -Infinity, -Infinity];
|
||||
let startPoint: Position, endPoint: Position;
|
||||
coordEach(geojson, (coord) => {
|
||||
startPoint ??= [coord[0], coord[1]];
|
||||
endPoint = coord;
|
||||
if (result[0] > coord[0]) {
|
||||
result[0] = coord[0];
|
||||
}
|
||||
if (result[1] > coord[1]) {
|
||||
result[1] = coord[1];
|
||||
}
|
||||
if (result[2] < coord[0]) {
|
||||
result[2] = coord[0];
|
||||
}
|
||||
if (result[3] < coord[1]) {
|
||||
result[3] = coord[1];
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function findStartAndEndPoints(geojson: GeoJsonObject): Position[] {
|
||||
const startEndPoints: Position[] = [];
|
||||
|
||||
(geojson as FeatureCollection).features.forEach((feature) => {
|
||||
const geometry = feature.geometry;
|
||||
|
||||
if (geometry.type === "LineString") {
|
||||
const coords = geometry.coordinates as number[][];
|
||||
const start: [number, number] = [coords[0][0], coords[0][1]]; // First point
|
||||
const end: [number, number] = [
|
||||
coords[coords.length - 1][0],
|
||||
coords[coords.length - 1][1],
|
||||
]; // Last point
|
||||
startEndPoints.push(start);
|
||||
startEndPoints.push(end)
|
||||
} else if (geometry.type === "MultiLineString") {
|
||||
const coords = geometry.coordinates as number[][][];
|
||||
const start: [number, number] = [
|
||||
coords[0][0][0],
|
||||
coords[0][0][1],
|
||||
]; // First point of the first line
|
||||
const lastLine = coords[coords.length - 1];
|
||||
const end: [number, number] = [
|
||||
lastLine[lastLine.length - 1][0],
|
||||
lastLine[lastLine.length - 1][1],
|
||||
]; // Last point of the last line
|
||||
startEndPoints.push(start);
|
||||
startEndPoints.push(end)
|
||||
} else {
|
||||
console.warn(
|
||||
`Geometry type ${geometry.type} is not supported for start/end point extraction.`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return startEndPoints;
|
||||
}
|
||||
|
||||
function coordEach(geojson: GeoJSON, callback: (
|
||||
currentCoord: number[],
|
||||
coordIndex: number,
|
||||
featureIndex: number,
|
||||
multiFeatureIndex: number,
|
||||
geometryIndex: number
|
||||
) => void | false,
|
||||
excludeWrapCoord?: boolean,) {
|
||||
// Handles null Geometry -- Skips this GeoJSON
|
||||
if (geojson === null) return;
|
||||
var j,
|
||||
k,
|
||||
l,
|
||||
geometry,
|
||||
stopG,
|
||||
coords,
|
||||
geometryMaybeCollection,
|
||||
wrapShrink = 0,
|
||||
coordIndex = 0,
|
||||
isGeometryCollection,
|
||||
type = geojson.type,
|
||||
isFeatureCollection = type === "FeatureCollection",
|
||||
isFeature = type === "Feature",
|
||||
stop = isFeatureCollection ? (geojson as FeatureCollection).features.length : 1;
|
||||
|
||||
for (var featureIndex = 0; featureIndex < stop; featureIndex++) {
|
||||
geometryMaybeCollection = isFeatureCollection
|
||||
? (geojson as FeatureCollection).features[featureIndex].geometry
|
||||
: isFeature
|
||||
? (geojson as Feature).geometry
|
||||
: geojson;
|
||||
isGeometryCollection = geometryMaybeCollection
|
||||
? geometryMaybeCollection.type === "GeometryCollection"
|
||||
: false;
|
||||
stopG = isGeometryCollection
|
||||
? (geometryMaybeCollection as GeometryCollection).geometries.length
|
||||
: 1;
|
||||
|
||||
for (var geomIndex = 0; geomIndex < stopG; geomIndex++) {
|
||||
var multiFeatureIndex = 0;
|
||||
var geometryIndex = 0;
|
||||
geometry = isGeometryCollection
|
||||
? (geometryMaybeCollection as GeometryCollection).geometries[geomIndex]
|
||||
: geometryMaybeCollection;
|
||||
|
||||
// Handles null Geometry -- Skips this geometry
|
||||
if (geometry === null) continue;
|
||||
coords = (geometry as any).coordinates;
|
||||
var geomType = geometry.type;
|
||||
|
||||
wrapShrink =
|
||||
excludeWrapCoord &&
|
||||
(geomType === "Polygon" || geomType === "MultiPolygon")
|
||||
? 1
|
||||
: 0;
|
||||
|
||||
switch (geomType) {
|
||||
case null:
|
||||
break;
|
||||
case "Point":
|
||||
if (
|
||||
callback(
|
||||
coords,
|
||||
coordIndex,
|
||||
featureIndex,
|
||||
multiFeatureIndex,
|
||||
geometryIndex
|
||||
) === false
|
||||
)
|
||||
return false;
|
||||
coordIndex++;
|
||||
multiFeatureIndex++;
|
||||
break;
|
||||
case "LineString":
|
||||
case "MultiPoint":
|
||||
for (j = 0; j < coords.length; j++) {
|
||||
if (
|
||||
callback(
|
||||
coords[j],
|
||||
coordIndex,
|
||||
featureIndex,
|
||||
multiFeatureIndex,
|
||||
geometryIndex
|
||||
) === false
|
||||
)
|
||||
return false;
|
||||
coordIndex++;
|
||||
if (geomType === "MultiPoint") multiFeatureIndex++;
|
||||
}
|
||||
if (geomType === "LineString") multiFeatureIndex++;
|
||||
break;
|
||||
case "Polygon":
|
||||
case "MultiLineString":
|
||||
for (j = 0; j < coords.length; j++) {
|
||||
for (k = 0; k < coords[j].length - wrapShrink; k++) {
|
||||
if (
|
||||
callback(
|
||||
coords[j][k],
|
||||
coordIndex,
|
||||
featureIndex,
|
||||
multiFeatureIndex,
|
||||
geometryIndex
|
||||
) === false
|
||||
)
|
||||
return false;
|
||||
coordIndex++;
|
||||
}
|
||||
if (geomType === "MultiLineString") multiFeatureIndex++;
|
||||
if (geomType === "Polygon") geometryIndex++;
|
||||
}
|
||||
if (geomType === "Polygon") multiFeatureIndex++;
|
||||
break;
|
||||
case "MultiPolygon":
|
||||
for (j = 0; j < coords.length; j++) {
|
||||
geometryIndex = 0;
|
||||
for (k = 0; k < coords[j].length; k++) {
|
||||
for (l = 0; l < coords[j][k].length - wrapShrink; l++) {
|
||||
if (
|
||||
callback(
|
||||
coords[j][k][l],
|
||||
coordIndex,
|
||||
featureIndex,
|
||||
multiFeatureIndex,
|
||||
geometryIndex
|
||||
) === false
|
||||
)
|
||||
return false;
|
||||
coordIndex++;
|
||||
}
|
||||
geometryIndex++;
|
||||
}
|
||||
multiFeatureIndex++;
|
||||
}
|
||||
break;
|
||||
case "GeometryCollection":
|
||||
for (j = 0; j < (geometry as GeometryCollection).geometries.length; j++)
|
||||
if (
|
||||
coordEach((geometry as GeometryCollection).geometries[j], callback, excludeWrapCoord) ===
|
||||
false
|
||||
)
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unknown Geometry Type");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,21 +2,22 @@ import GPX from "$lib/models/gpx/gpx";
|
||||
import { Trail } from "$lib/models/trail";
|
||||
import { Waypoint } from "$lib/models/waypoint";
|
||||
import { currentUser } from "$lib/stores/user_store";
|
||||
import { kml, tcx } from "$lib/vendor/toGeoJSON/toGeoJSON";
|
||||
import { gpx, kml, tcx } from "$lib/vendor/toGeoJSON/toGeoJSON";
|
||||
import cryptoRandomString from "crypto-random-string";
|
||||
import { get } from "svelte/store";
|
||||
//@ts-ignore
|
||||
import EasyFit from "$lib/vendor/easy-fit/easy-fit"
|
||||
import { browser } from "$app/environment";
|
||||
import Track from "$lib/models/gpx/track";
|
||||
import TrackSegment from "$lib/models/gpx/track-segment";
|
||||
import GPXWaypoint from "$lib/models/gpx/waypoint";
|
||||
import { browser } from "$app/environment";
|
||||
import * as xmldom from 'xmldom'
|
||||
import type { Feature, FeatureCollection, GeoJsonProperties, Position } from 'geojson';
|
||||
import EasyFit from "$lib/vendor/easy-fit/easy-fit";
|
||||
import type { GeoJSON, Feature, FeatureCollection, GeoJsonProperties, Position } from 'geojson';
|
||||
import * as xmldom from 'xmldom';
|
||||
import { bbox } from "./geojson_util";
|
||||
|
||||
|
||||
export async function gpx2trail(gpxString: string, fallbackName?: string) {
|
||||
|
||||
|
||||
const gpx = await GPX.parse(gpxString);
|
||||
|
||||
if (gpx instanceof Error) {
|
||||
@@ -281,4 +282,13 @@ export function isFITFile(buffer: ArrayBuffer) {
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function toGeoJson(gpxData: string) {
|
||||
const parser = browser ? new DOMParser() : new xmldom.DOMParser();
|
||||
const geojson = gpx(
|
||||
parser.parseFromString(gpxData, "text/xml"),
|
||||
) as GeoJSON;
|
||||
geojson.bbox = bbox(geojson)
|
||||
return geojson
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import type { Waypoint } from "$lib/models/waypoint";
|
||||
import M from "maplibre-gl";
|
||||
|
||||
export class FontawesomeMarker extends M.Marker {
|
||||
constructor(options: { icon: string, fontSize?: string, width?: number, backgroundColor?: string, fontColor?: string }, markerOptions?: M.MarkerOptions) {
|
||||
const element = document.createElement('div')
|
||||
element.className = `cursor-pointer flex items-center justify-center w-${options.width ?? 7} aspect-square bg-${options.backgroundColor ?? "gray-500"} rounded-full text-${options.fontSize ?? "normal"}`
|
||||
super({ element: element, ...markerOptions });
|
||||
|
||||
const {
|
||||
icon,
|
||||
} = options
|
||||
|
||||
const iconElementString = `<i class="text-${options.fontColor ?? "white"} ${icon}"></i>`
|
||||
this._element.insertAdjacentHTML('beforeend', iconElementString)
|
||||
}
|
||||
}
|
||||
|
||||
export function createMarkerFromWaypoint(waypoint: Waypoint, onDragEnd?: (marker: M.Marker) => void): FontawesomeMarker {
|
||||
const marker = new FontawesomeMarker({
|
||||
icon: `fa fa-${waypoint.icon}`,
|
||||
}, {
|
||||
draggable: onDragEnd != null,
|
||||
color: "#6b7280"
|
||||
|
||||
})
|
||||
const popup = new M.Popup({ offset: 25, closeButton: false }).setHTML(
|
||||
"<b>" +
|
||||
waypoint.name +
|
||||
"</b>" +
|
||||
(waypoint.description && waypoint.description.length > 0
|
||||
? "<br>" + waypoint.description
|
||||
: ""),
|
||||
);
|
||||
marker
|
||||
.setLngLat([waypoint.lon, waypoint.lat])
|
||||
.setPopup(popup)
|
||||
|
||||
if (onDragEnd) {
|
||||
marker.on("dragend", () => onDragEnd(marker));
|
||||
}
|
||||
|
||||
return marker;
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
import { type ControlPosition, type IControl } from "maplibre-gl";
|
||||
import * as M from "maplibre-gl";
|
||||
import { ElevationProfile, type ElevationProfileOptions } from "./elevationprofile";
|
||||
// @ts-ignore
|
||||
import type { GeoJsonObject } from "geojson";
|
||||
import type { Waypoint } from "$lib/models/waypoint";
|
||||
|
||||
/**
|
||||
* Elevation profile control options
|
||||
*/
|
||||
export type ElevationProfileControlOptions = ElevationProfileOptions & {
|
||||
/**
|
||||
* If `true`, the elevation profile control will be visible as soon as it's ready.
|
||||
* If `false`, a click on the control button (or a programmatic call to `.showProfile()`)
|
||||
* will be neccesary to show the profile.
|
||||
*
|
||||
* Default: `false`
|
||||
*/
|
||||
visible?: boolean;
|
||||
/**
|
||||
* Size of the profile as a CSS rule.
|
||||
* This `size` will be the `width` if the `.position` is "left" or "right",
|
||||
* and will be the `height` if the `.position` is "top" or "bottom".
|
||||
*
|
||||
* Default: `"30%"`
|
||||
*/
|
||||
size?: string;
|
||||
/**
|
||||
* Position of the elevation profile chart when shown.
|
||||
*
|
||||
* Default: `"botton"`
|
||||
*/
|
||||
position?: "top" | "left" | "right" | "bottom";
|
||||
/**
|
||||
* Show the control button. If can be handy to hide it, especially if the profile is displayed
|
||||
* in a custom container and that its visiblity is managed by logic external to this control.
|
||||
*
|
||||
* Default: `true`
|
||||
*/
|
||||
showButton?: boolean;
|
||||
/**
|
||||
* A CSS class to add to the container. This is especially relevant when the options `.container` is not provided.
|
||||
* Important: if provided, no styling is added by this control and even placement will have to be managed by external CSS.
|
||||
*
|
||||
* Default: `""`
|
||||
*/
|
||||
containerClass?: string;
|
||||
|
||||
/**
|
||||
* DIV element to contain the control.
|
||||
* Important: if provided, no styling is added by this control.
|
||||
* Default: automatically created inside the map container
|
||||
*/
|
||||
container?: string | HTMLDivElement;
|
||||
};
|
||||
|
||||
export class ElevationProfileControl implements IControl {
|
||||
private map?: M.Map;
|
||||
private buttonContainer?: HTMLDivElement;
|
||||
private toggleButton?: HTMLButtonElement;
|
||||
private isProfileShown = false;
|
||||
private iconSpan?: HTMLSpanElement;
|
||||
|
||||
private profileContainer?: HTMLDivElement;
|
||||
private settings: ElevationProfileControlOptions;
|
||||
private data: GeoJsonObject | null = null;
|
||||
private elevationProfileChart?: ElevationProfile;
|
||||
|
||||
constructor(options: ElevationProfileControlOptions = {}) {
|
||||
if (typeof window === "undefined")
|
||||
throw new Error("This pluggin must be mounted client-side");
|
||||
this.settings = { ...options };
|
||||
}
|
||||
|
||||
toggleTheme(options: ElevationProfileControlOptions) {
|
||||
this.settings = { ...this.settings, ...options };
|
||||
this.elevationProfileChart?.toggleTheme(this.settings)
|
||||
}
|
||||
|
||||
getContainer(): HTMLDivElement | undefined {
|
||||
return this.profileContainer;
|
||||
}
|
||||
|
||||
onAdd(map: M.Map): HTMLElement {
|
||||
this.map = map;
|
||||
|
||||
this.buttonContainer = document.createElement("div");
|
||||
|
||||
if (this.settings.showButton === false) {
|
||||
this.buttonContainer.style.setProperty("display", "none");
|
||||
}
|
||||
|
||||
this.buttonContainer.classList.add(
|
||||
"maplibregl-ctrl",
|
||||
"maplibregl-ctrl-group"
|
||||
);
|
||||
this.toggleButton = document.createElement("button");
|
||||
this.buttonContainer.appendChild(this.toggleButton);
|
||||
this.iconSpan = document.createElement("i");
|
||||
this.iconSpan.classList.add("fa", "fa-chart-line", "text-black");
|
||||
this.toggleButton.appendChild(this.iconSpan);
|
||||
this.toggleButton.addEventListener("click", this.toggleProfile.bind(this));
|
||||
const mapContainer = map.getContainer();
|
||||
const size = this.settings.size ?? "30%";
|
||||
|
||||
if (this.settings.container) {
|
||||
const tmpContainer =
|
||||
typeof this.settings.container === "string"
|
||||
? document.getElementById(this.settings.container)
|
||||
: this.settings.container;
|
||||
if (!tmpContainer) throw new Error("The provided container is invalid");
|
||||
this.profileContainer = tmpContainer as HTMLDivElement;
|
||||
} else {
|
||||
this.profileContainer = document.createElement("div");
|
||||
this.profileContainer.style.setProperty("display", "none");
|
||||
|
||||
if (!this.settings.containerClass) {
|
||||
this.profileContainer.classList.add(this.settings.backgroundColor ?? "white")
|
||||
|
||||
this.profileContainer.style.setProperty("position", "absolute");
|
||||
|
||||
if (this.settings.position === "bottom" || !this.settings.position) {
|
||||
// To prevent clashing with MapTiler logo and attribution control
|
||||
this.settings.paddingBottom = this.settings.paddingBottom ?? 35;
|
||||
this.profileContainer.style.setProperty("width", "100%");
|
||||
this.profileContainer.style.setProperty("height", size);
|
||||
this.profileContainer.style.setProperty("bottom", "0");
|
||||
} else if (this.settings.position === "top") {
|
||||
this.profileContainer.style.setProperty("width", "100%");
|
||||
this.profileContainer.style.setProperty("height", size);
|
||||
this.profileContainer.style.setProperty("top", "0");
|
||||
} else if (this.settings.position === "left") {
|
||||
// To prevent clashing with MapTiler logo and attribution control
|
||||
this.settings.paddingBottom = this.settings.paddingBottom ?? 35;
|
||||
this.profileContainer.style.setProperty("width", size);
|
||||
this.profileContainer.style.setProperty("height", "100%");
|
||||
this.profileContainer.style.setProperty("left", "0");
|
||||
} else if (this.settings.position === "right") {
|
||||
// To prevent clashing with MapTiler logo and attribution control
|
||||
this.settings.paddingBottom = this.settings.paddingBottom ?? 35;
|
||||
this.profileContainer.style.setProperty("width", size);
|
||||
this.profileContainer.style.setProperty("height", "100%");
|
||||
this.profileContainer.style.setProperty("right", "0");
|
||||
}
|
||||
}
|
||||
|
||||
const waypointContainer = document.createElement("div")
|
||||
waypointContainer.className = "absolute w-full"
|
||||
waypointContainer.id = "waypoint-container"
|
||||
|
||||
this.profileContainer.append(waypointContainer);
|
||||
|
||||
mapContainer.appendChild(this.profileContainer);
|
||||
}
|
||||
|
||||
if (this.settings.containerClass) {
|
||||
this.profileContainer.classList.add(this.settings.containerClass);
|
||||
}
|
||||
|
||||
this.elevationProfileChart = new ElevationProfile(
|
||||
this.profileContainer,
|
||||
this.settings
|
||||
);
|
||||
|
||||
if (this.settings.visible) {
|
||||
this.showProfile();
|
||||
}
|
||||
|
||||
return this.buttonContainer;
|
||||
}
|
||||
|
||||
private toggleProfile() {
|
||||
if (!this.profileContainer) return;
|
||||
|
||||
if (this.isProfileShown) {
|
||||
this.hideProfile();
|
||||
} else {
|
||||
this.showProfile();
|
||||
}
|
||||
}
|
||||
|
||||
showProfile() {
|
||||
this.profileContainer?.style.setProperty("display", "inherit");
|
||||
this.isProfileShown = true;
|
||||
}
|
||||
|
||||
hideProfile() {
|
||||
this.profileContainer?.style.setProperty("display", "none");
|
||||
this.isProfileShown = false;
|
||||
}
|
||||
|
||||
onRemove(): void {
|
||||
// remove button
|
||||
if (this.buttonContainer?.parentNode) {
|
||||
this.buttonContainer.parentNode.removeChild(this.buttonContainer);
|
||||
}
|
||||
this.map = undefined;
|
||||
this.buttonContainer = undefined;
|
||||
this.toggleButton = undefined;
|
||||
this.isProfileShown = false;
|
||||
}
|
||||
|
||||
getDefaultPosition?: (() => ControlPosition) | undefined;
|
||||
|
||||
async setData(data: GeoJsonObject, waypoints?: Waypoint[]) {
|
||||
if (!this.map || !this.elevationProfileChart) {
|
||||
throw new Error(
|
||||
"The Elevation Profile Control needs to be mounted on a map instance before setting any data."
|
||||
);
|
||||
}
|
||||
|
||||
this.data = data;
|
||||
|
||||
if (!this.data) return;
|
||||
|
||||
this.elevationProfileChart.setData(this.data, waypoints);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,47 @@
|
||||
import { haversineDistance } from "$lib/models/gpx/utils";
|
||||
import type {
|
||||
Position
|
||||
} from "geojson";
|
||||
|
||||
|
||||
export function haversineCumulatedDistanceWgs84(path: Position[]): number[] {
|
||||
if (path.length < 2) {
|
||||
return [];
|
||||
}
|
||||
|
||||
let totalDistance = 0;
|
||||
const distances: number[] = [0];
|
||||
|
||||
for (let i = 0; i < path.length - 1; i++) {
|
||||
const [lon1, lat1] = path[i];
|
||||
const [lon2, lat2] = path[i + 1];
|
||||
|
||||
totalDistance += haversineDistance(lat1, lon1, lat2, lon2);
|
||||
distances.push(totalDistance);
|
||||
}
|
||||
|
||||
return distances; // Array of cumulative distances in meters
|
||||
}
|
||||
|
||||
export function smoothElevations(positions: Position[], windowSize: number): Position[] {
|
||||
// Ensure windowSize is valid (at least 1)
|
||||
if (windowSize < 1) throw new Error("Window size must be at least 1.");
|
||||
|
||||
// Create a new array with smoothed elevations
|
||||
return positions.map((pos, i, arr) => {
|
||||
const start = Math.max(0, i - Math.floor(windowSize / 2)); // Start index for the window
|
||||
const end = Math.min(arr.length, i + Math.floor(windowSize / 2) + 1); // End index for the window
|
||||
const segment = arr.slice(start, end); // Extract the positions in the window
|
||||
|
||||
// Calculate the weighted moving average of elevations
|
||||
const weights = segment.map((_, idx) => idx + 1); // Increasing weights: 1, 2, 3...
|
||||
const elevations = segment.map(p => p[2]); // Extract elevations
|
||||
const weightedSum = elevations.reduce((sum, elevation, idx) => sum + elevation * weights[idx], 0);
|
||||
const weightTotal = weights.reduce((sum, weight) => sum + weight, 0);
|
||||
|
||||
const smoothedElevation = weightedSum / weightTotal; // Weighted average elevation
|
||||
|
||||
// Return a new Position with the smoothed elevation
|
||||
return [pos[0], pos[1], smoothedElevation] as Position;
|
||||
});
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
style="height: calc(100dvh - 120px); font-size: 4rem"
|
||||
>
|
||||
<img
|
||||
class="absolute top-1/2 left-1/2 aspect-square rounded-xl object-cover"
|
||||
class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 aspect-square rounded-xl object-cover"
|
||||
width="500"
|
||||
src="/imgs/error.webp"
|
||||
alt="Default error img"
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<script lang="ts">
|
||||
import MapWithElevation from "$lib/components/trail/map_with_elevation.svelte";
|
||||
import MapWithElevationMaplibre from "$lib/components/trail/map_with_elevation_maplibre.svelte";
|
||||
import TrailInfoPanel from "$lib/components/trail/trail_info_panel.svelte";
|
||||
import { trail } from "$lib/stores/trail_store";
|
||||
import "$lib/vendor/leaflet-elevation/src/index.css";
|
||||
import type { Marker } from "leaflet";
|
||||
import "leaflet.awesome-markers/dist/leaflet.awesome-markers.css";
|
||||
import "leaflet/dist/leaflet.css";
|
||||
import * as M from "maplibre-gl";
|
||||
import "photoswipe/style.css";
|
||||
import { _ } from "svelte-i18n";
|
||||
|
||||
let markers: Marker[];
|
||||
let markers: M.Marker[];
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
@@ -18,7 +18,7 @@
|
||||
<main class="grid grid-cols-1 md:grid-cols-[458px_1fr] gap-x-1 gap-y-4">
|
||||
<TrailInfoPanel trail={$trail} {markers}></TrailInfoPanel>
|
||||
<div id="trail-details" class="sticky top-[62px]">
|
||||
<MapWithElevation trail={$trail} bind:markers></MapWithElevation>
|
||||
<MapWithElevationMaplibre trail={$trail} bind:markers></MapWithElevationMaplibre>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<script>
|
||||
import MapWithElevationMaplibre from "$lib/components/trail/map_with_elevation_maplibre.svelte";
|
||||
import { onMount } from "svelte";
|
||||
export let data;
|
||||
|
||||
</script>
|
||||
|
||||
<MapWithElevationMaplibre trail={data.trail}></MapWithElevationMaplibre>
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { Trail } from "$lib/models/trail";
|
||||
import { trails_show } from "$lib/stores/trail_store";
|
||||
|
||||
export const load = async ({ params, fetch }) => {
|
||||
const t: Trail = await trails_show("yesm2tqc6jok8jq", true, fetch)
|
||||
|
||||
|
||||
return { trail: t }
|
||||
};
|
||||
@@ -296,7 +296,6 @@
|
||||
elevation_loss: $form.elevation_loss,
|
||||
duration: $form.duration ? $form.duration * 60 : undefined,
|
||||
});
|
||||
console.log(selectedFile.type);
|
||||
|
||||
log.expand.gpx_data = gpxData;
|
||||
const blob = new Blob([gpxData], { type: selectedFile.type });
|
||||
|
||||
@@ -5,7 +5,9 @@ export default {
|
||||
extend: {
|
||||
colors: {
|
||||
'background': 'rgba(var(--background))',
|
||||
'background-inverse': 'rgba(var(--background-inverse))',
|
||||
'content': 'rgba(var(--content))',
|
||||
'content-inverse': 'rgba(var(--content-inverse))',
|
||||
|
||||
'primary': 'rgba(var(--primary))',
|
||||
'primary-hover': 'rgba(var(--primary-hover))',
|
||||
|
||||
Reference in New Issue
Block a user