Porównaj commity

...

134 Commity

Autor SHA1 Wiadomość Data
Manuel Kasper 2bff821305 Change line pattern and color for borders to better differentiate them from tracks/paths 2024-05-27 16:06:09 +02:00
Manuel Kasper 817866cdb1 Add diff against current original MapTiler stylesheet to repo for future reference 2024-05-27 15:58:36 +02:00
Manuel Kasper d9481d5994 Adjust popup top padding to previous (MapBox) level 2024-05-27 15:41:45 +02:00
Manuel Kasper e40c5a8f57 Switch mapbox-gl-draw branch 2024-05-27 15:35:35 +02:00
Manuel Kasper 0b6da458b2 Remove MapBox GL JS 2024-05-27 15:08:18 +02:00
Manuel Kasper 40ba91d5f6 Handle missing map type gracefully 2024-05-27 14:57:08 +02:00
Manuel Kasper 0ae7913f9a Switch everything to MapTiler 2024-05-27 14:49:47 +02:00
Manuel Kasper 2dbcda5f79 Different MapTiler maps depending on units 2024-05-27 11:45:30 +02:00
Manuel Kasper 7b52c12b45 New map IDs 2024-05-27 10:59:28 +02:00
Manuel Kasper 8bb8206afb Merge branch 'master' into beta 2024-05-21 20:51:40 +02:00
Manuel Kasper d4711256b8 Add AZ download button 2024-05-21 20:42:43 +02:00
Manuel Kasper df0b8752e4 Merge branch 'master' into beta 2024-05-14 08:43:53 +02:00
Manuel Kasper 01d95196d8 Update AZ info 2024-05-14 08:43:47 +02:00
Manuel Kasper 28261e1533 Update packages 2024-05-06 21:55:57 +02:00
Manuel Kasper 80a90b9e85 Force package update 2024-05-06 20:53:43 +02:00
Manuel Kasper 5d0dd739b7 Fix map options for OpenMapTiles 2024-05-06 19:45:33 +02:00
Manuel Kasper 16a540341e Add support for MapTiler maps (tentative) 2024-05-06 19:43:29 +02:00
Manuel Kasper 090e634a86 Ensure consistency in case of component reuse 2024-04-26 16:46:01 +02:00
Manuel Kasper fcb83b4fd3 Highlight/link database callsign instead 2024-04-26 16:41:02 +02:00
Manuel Kasper 62bd0ed608 Show database callsign for first activators in case it is not the same (e.g. for activations with club callsigns) 2024-04-26 16:36:28 +02:00
Manuel Kasper 55d643db25 Upgrade to Node 20 and some dependencies 2024-04-26 12:39:31 +01:00
Manuel Kasper 031379eab9 Revert "Add option for legacy compatibility" (not compatible with DO)
This reverts commit ea0d0a0a2f.
2024-04-26 11:07:54 +01:00
Manuel Kasper ea0d0a0a2f Add option for legacy compatibility 2024-04-26 11:05:44 +01:00
Manuel Kasper c97745a1d1 Add info about W7W/KG AZ boundaries 2024-04-11 10:17:08 +02:00
Manuel Kasper 6052ba1004 Show date on which a route was posted (suggested by HB9DIZ) 2024-03-25 13:44:24 +01:00
Manuel Kasper 4214371ff8 Report map session only on first actual map load per application init 2024-03-01 22:17:34 +01:00
Manuel Kasper 3040dbad3e Improve error message 2024-02-27 16:12:57 +01:00
Manuel Kasper 5932baea4f Count app inits also (relevant for potential future MapTiler session based billing) 2024-02-26 11:30:00 +01:00
Manuel Kasper 3e7130bc0b Send map type when tracking map sessions 2024-02-21 12:14:34 +01:00
Manuel Kasper 36103f2d3b Call API to track number of map sessions (to evaluate move to MapTiler Cloud) 2024-02-21 11:40:00 +01:00
Manuel Kasper dbd2b2c537 Show activation zone boundaries also on OpenMapTiles map (#25) 2024-02-21 10:33:35 +01:00
Manuel Kasper d02fe4fdbf Add activation zones for OE (#25), switch to gray basemap.at map for contours, add info dialog about basemap.at for users from Austrian IP addresses. Thanks @g84ycm! 2024-02-20 09:58:14 +01:00
Manuel Kasper a4073fba02 Update axios, fix display of "built-in" tracks 2023-12-28 17:12:09 +01:00
Manuel Kasper 0724d9200e Update dependencies, fix saving drawn tracks 2023-12-04 16:26:02 +01:00
Manuel Kasper 5c57070b8a Revert api-db2 changes for the time being (no access for sotlas SSO token) 2023-10-19 07:48:43 +02:00
Manuel Kasper 5309668c5e Handle no bonus correctly 2023-10-18 21:29:02 +02:00
Manuel Kasper 64a6a57f03 Reposition tooltip on mobile 2023-10-18 21:16:42 +02:00
Manuel Kasper 62af0822da Show bonus season on hover 2023-10-18 21:11:12 +02:00
Manuel Kasper 0b96d3c33e Merge branch 'master' into beta 2023-10-18 21:10:38 +02:00
Manuel Kasper c2c6ea1ae7 Fix random switching to other webcam popup 2023-10-16 12:10:39 +02:00
Manuel Kasper 2794e12210 Add bug info for iOS 17 users 2023-10-07 22:03:50 +02:00
Manuel Kasper b19f9d5ecc Use user ID of currently logged in user 2023-09-28 11:29:36 +02:00
Manuel Kasper 53bff389c3 Switch those requests to api-db2 that have already required authentication before
(to maintain public/not-logged-in access to the list of activations for activator details pages)
2023-09-28 11:22:20 +02:00
Manuel Kasper 0434400726 Switch to Windy v3 webcam API due to upcoming deprecation of v2 API 2023-09-28 10:23:56 +02:00
Manuel Kasper 0c6d6f52c7 Add basic background world map to country-specific maps to avoid "blank screen" when outside the selected map's coverage area 2023-09-19 16:16:14 +02:00
Manuel Kasper a978ab19ba Add basemap.at map option (#22), and add link to Austrian Map 2023-09-19 11:01:30 +02:00
Manuel Kasper d458738639 Add info about hiking difficulty 2023-08-19 18:10:05 +02:00
Manuel Kasper 4f94f6ad45 Revert "Show photo waypoints export button also on mobile" (doesn't seem to work on iPhone)
This reverts commit f4c6263f89.
2023-08-02 20:52:31 +02:00
Manuel Kasper f4c6263f89 Show photo waypoints export button also on mobile 2023-08-02 20:49:25 +02:00
Manuel Kasper f390f247a0 Slight legibility improvement 2023-07-30 13:19:49 +02:00
Manuel Kasper 9043e35fda Don't show old photos that are missing an uploadDate 2023-07-24 16:47:19 +02:00
Manuel Kasper 5c1c82d3ad Show warning when uploading low resolution photos 2023-07-21 16:16:18 +02:00
Manuel Kasper ba04fdc2c9 Fix allow ?? region code 2023-06-11 20:00:23 +02:00
Manuel Kasper fa54e7f3f3 Allow -??? summit numbers and XX/?? region codes as well 2023-06-11 19:55:56 +02:00
Manuel Kasper 62219867eb Allow -XXX style references in alerts 2023-06-11 19:47:07 +02:00
Manuel Kasper 05765e9562 Honor line breaks in SMP route descriptions 2023-05-30 20:03:02 +02:00
Manuel Kasper ed7b27ae8b Update caniuse, remove branch from footer, bump SOTA DB copyright 2023-05-10 16:31:43 +02:00
Manuel Kasper ce1a0826ec Update vue-template-compiler 2023-05-10 16:17:11 +02:00
Manuel Kasper 6476b646d6 Increase enlarge map height. Update frappe-charts 2023-05-10 15:53:16 +02:00
Manuel Kasper d6cabc6c30 Attempt to fix route 2023-05-10 15:26:07 +02:00
Manuel Kasper b32884364c JS version compatibility, remove version number from footer 2023-05-10 15:17:41 +02:00
Manuel Kasper 2e71728a4e Add public path to vue-router 2023-05-10 15:10:39 +02:00
Manuel Kasper 6e3f6abfce Remove old/unnecessary dependency; add support for different public path (beta) 2023-05-10 14:47:31 +02:00
Manuel Kasper 69e5436257 Downgrade core-js for vue2 compatibility. Update vue-router 2023-05-10 14:39:34 +02:00
Manuel Kasper baaa496ea3 Update some components 2023-05-10 14:25:38 +02:00
Manuel Kasper 52d050b2bc Remove node option for DO 2023-05-08 14:50:28 +02:00
Manuel Kasper 8b2d179486 Fix IGN map link 2023-05-08 14:45:47 +02:00
Manuel Kasper 1df937b854 Fix error message text (#20) 2023-04-30 09:57:10 +02:00
Manuel Kasper b9d1cbceb7 Fix building with recent Node/NPM versions 2023-04-30 09:56:50 +02:00
Manuel Kasper 71d3ad6b4b Disable link if not logged in 2023-03-25 21:03:22 +01:00
Manuel Kasper a419ab5dcf Direct people to summits.sota.org.uk to add an article 2023-03-25 20:46:32 +01:00
Manuel Kasper 3d58d3094b
Add CalTopo map 2023-02-14 18:03:15 -10:00
Manuel Kasper 3a8d92df84
Add Peakbagger.com link 2023-02-14 17:38:24 -10:00
Manuel Kasper 2192dff486 Rename summit code to summit ref. for consistency with SOTA terminology 2023-01-13 09:26:15 +01:00
Manuel Kasper bcd6f95e0c Show error message from SOTAwatch, if any 2022-12-13 17:31:34 +01:00
Manuel Kasper cf2e411ad2 Make filtered-out summits less obtrusive 2022-12-04 17:32:02 +01:00
Manuel Kasper 12251b36f6 Show filtered summits on main map with a small, faint circle (#18) 2022-11-12 11:57:09 +01:00
Manuel Kasper cba61ea997 Remove special handling for comma as it causes problems on iOS 16 2022-10-23 18:36:17 +01:00
Manuel Kasper 12f64b1f3e Attempt to improve responsive loading and sizes on mobile 2022-10-15 21:36:44 +01:00
Manuel Kasper cc20e47f42 Fix tag order to comply with schema 2022-10-06 17:09:29 +02:00
Manuel Kasper 121d5306e7 Fix thumbnail width on mobile devices 2022-10-02 18:47:25 +02:00
Manuel Kasper d61719b091 Set width/height of thumbnail to avoid content reflow while loading 2022-10-02 17:38:45 +02:00
Manuel Kasper 70d5f655ca Change AZ color again 2022-09-29 19:54:54 +02:00
Manuel Kasper 962a7ebbd9 Increase contrast 2022-09-24 11:18:52 +02:00
Manuel Kasper 2a1a0cf4fd Change AZ color so as not to clash with slope classes 2022-09-24 11:10:55 +02:00
Manuel Kasper dafa17c181
Merge pull request #17 from ntilley905/patch-1
Remove Gaia GPS Default Layer
2022-09-20 21:40:11 +02:00
Nathan Tilley 909cf863a7
Remove Gaia GPS Default Layer 2022-09-20 09:50:07 -07:00
Manuel Kasper 8e02be05b2 Fix activator map (thanks DM3FAM for the report) 2022-08-11 21:44:03 +02:00
Manuel Kasper 6495b4c641 Avoid problems caused by mini map reuse 2022-08-09 23:21:14 +02:00
Manuel Kasper 30bd4a1a25 Better highlighting in case of multiple overlapping routes 2022-08-09 21:55:42 +02:00
Manuel Kasper 227afdb918 Make elevation API URL configurable via env var 2022-08-06 22:53:30 +02:00
Manuel Kasper 7e715070cc Update swisstopo maps 2022-08-06 17:52:35 +02:00
Manuel Kasper a36761b70c Update SSO token before attempting to load profile 2022-08-06 17:26:30 +02:00
Manuel Kasper 1dc744460a Include SMP track notes in GPX export 2022-08-05 15:23:28 +02:00
Manuel Kasper 99f17befc0 Update photos URL to CDN 2022-08-05 10:22:54 +02:00
Manuel Kasper 2698ec4284 Make api and images URL configurable via environment variables 2022-08-03 10:37:10 +02:00
Manuel Kasper d21213376c Generate icons before build 2022-08-03 10:00:16 +02:00
Manuel Kasper 262d492c2d Update vue/vue-router 2022-08-03 09:57:36 +02:00
Manuel Kasper ed5f09b168 Update sass 2022-08-03 09:51:20 +02:00
Manuel Kasper c1028b4df4 Use custom branch for vue-mapbox 2022-08-03 09:32:08 +02:00
Manuel Kasper 7f988711d7 Update package-lock.json 2022-08-03 09:26:45 +02:00
Manuel Kasper 9fea21d761 Update URL 2022-08-02 13:57:42 +02:00
Manuel Kasper 5e60b974f3 Move original size photos to Backblaze (S3 compatible storage) 2022-08-02 13:28:55 +02:00
Manuel Kasper 705319b53b Show error message when posting spot/alert fails 2022-07-23 20:32:08 +02:00
Manuel Kasper 80bfa01d00 Improve visibility of GPS tracks 2022-07-22 10:04:04 +02:00
Manuel Kasper 7e48e62259 Fix loading new region (#16) 2022-06-07 20:31:21 +02:00
Manuel Kasper 4b827c1d16 Add option to show alerts on map and in summit popups 2022-05-25 10:31:25 +02:00
Manuel Kasper a01ae83e5b Fix activator map for extreme latitudes/longitudes 2022-05-13 21:31:20 +02:00
Manuel Kasper bfe3eb4f6f Update some modules 2022-05-13 21:30:54 +02:00
Manuel Kasper 0ba7681260 Fix swapping of from/to numbers 2022-05-07 12:45:10 +02:00
Manuel Kasper f8560f551e Add Norkart 2022-05-04 14:05:42 +02:00
Manuel Kasper c6cd6cc02c Add attributions for raster maps 2022-05-04 13:32:47 +02:00
Manuel Kasper 057c3b2d30 Add TopoSvalbard base map 2022-05-04 13:25:51 +02:00
Manuel Kasper 9b3335b549 Add solar data history 2022-04-22 17:40:19 +02:00
Manuel Kasper 0ba7871914 Fix logo size on mobile devices 2022-04-15 19:38:30 +02:00
Manuel Kasper 88c54a4910 Show solar data also on smaller screens 2022-04-15 19:32:06 +02:00
Manuel Kasper f0e40fc88e Color K value only 2022-04-14 20:59:18 +02:00
Manuel Kasper cb8d84e924 Swap K/A order 2022-04-09 10:35:46 +02:00
Manuel Kasper 4f9b9a1791 Update package.lock (after npm upgrade) 2022-04-07 21:58:06 +02:00
Manuel Kasper b71d531775 Show solar data in navigation bar (if screen is big enough) 2022-04-07 21:36:11 +02:00
Manuel Kasper 531671696a Trim callsign for display also 2022-02-13 16:46:54 +01:00
Manuel Kasper f78a44722a Handle callsigns with leading/trailing spaces 2022-02-13 16:45:43 +01:00
Manuel Kasper 48aff99550 Add swisstopo Aerial (SWISSIMAGE) map choice 2022-02-13 09:49:31 +01:00
Manuel Kasper 3c8dfdde23 Add more GHz bands 2021-10-05 17:19:53 +02:00
Manuel Kasper 9015757960 Translate swisstopo map options to English 2021-09-29 10:47:00 +02:00
Manuel Kasper fe1200e1e0 Use more common term for DEM resolution 2021-09-27 17:07:26 +02:00
Manuel Kasper 2404162b01 Add note about activator responsibility for being in AZ 2021-09-27 16:46:02 +02:00
Manuel Kasper 2f23cfdf0b Add info about AZ data source 2021-09-27 16:02:59 +02:00
Manuel Kasper 03c1c23a7d Move AZ layer down in Z order 2021-09-27 14:34:11 +02:00
Manuel Kasper 429f2e5c48 Add activation zone display for HB 2021-09-27 14:28:15 +02:00
Manuel Kasper 64c684d4ad Add link to Activation Zone Estimator
Change some links to https
2021-09-27 11:13:07 +02:00
Manuel Kasper e5953ab584 Attempt to fix frequency comma input problem in some locales 2021-09-20 19:50:40 +02:00
Manuel Kasper c189ce901d Add inputmode for numeric keyboard on iOS 2021-09-05 20:02:27 +02:00
Manuel Kasper a0494e442c Use correct terminology for first activations 2021-08-25 18:00:48 +02:00
80 zmienionych plików z 37777 dodań i 22404 usunięć

8
.env 100644
Wyświetl plik

@ -0,0 +1,8 @@
VUE_APP_API_URL="https://sotl.as/api"
VUE_APP_WSS_URL="wss://sotl.as/api"
VUE_APP_PHOTOS_URL="https://photos.sotl.as"
VUE_APP_PHOTOS_ORIGINAL_URL="https://sotlas-photos.s3.eu-central-003.backblazeb2.com/original"
VUE_APP_ELEVATION_API_URL="https://elevation.sotl.as/api"
VUE_APP_MAPTILER_KEY="iIWOzto6cj259kSj9cSV"
VUE_APP_AZ_URL="https://az.sotl.as"
PUBLIC_PATH=/

42262
package-lock.json wygenerowano

Plik diff jest za duży Load Diff

Wyświetl plik

@ -2,16 +2,19 @@
"name": "sotlas",
"version": "0.1.0",
"private": true,
"engines": {
"node": "20.x"
},
"scripts": {
"serve": "vue-cli-service serve",
"prebuild": "vsvg -s ./svg-icons -t ./src/compiled-icons",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"generate-icons": "vsvg -s ./svg-icons -t ./src/compiled-icons",
"deploy": "gzip -fk9 dist/js/*.js dist/css/*.css && rsync -av dist/* root@vs5.ksys.ch:/data/www",
"deploy:beta": "gzip -fk9 dist/js/*.js dist/css/*.css && rsync -av --delete dist/* root@vs5.ksys.ch:/data/www/beta"
"generate-icons": "vsvg -s ./svg-icons -t ./src/compiled-icons"
},
"dependencies": {
"@dsb-norge/vue-keycloak-js": "github:manuelkasper/vue-keycloak-js#sotlas",
"@dwayneparton/geojson-to-gpx": "^0.0.30",
"@fortawesome/fontawesome-svg-core": "^1.2.34",
"@fortawesome/free-brands-svg-icons": "^5.15.2",
"@fortawesome/free-solid-svg-icons": "^5.15.2",
@ -19,50 +22,49 @@
"@fortawesome/pro-solid-svg-icons": "^5.15.2",
"@fortawesome/vue-fontawesome": "^0.1.10",
"@mapbox/mapbox-gl-draw": "github:manuelkasper/mapbox-gl-draw#sotlas",
"@mapbox/togeojson": "^0.16.0",
"@maptiler/sdk": "^2.0.3",
"@tmcw/togeojson": "^3.2.0",
"axios": "^0.21.1",
"axios": "^1.6.8",
"buefy": "^0.8.20",
"cheap-ruler": "^2.5.1",
"core-js": "^2.6.12",
"filepond": "^4.25.1",
"core-js": "^3.37.0",
"filepond": "^4.30.4",
"filepond-plugin-file-validate-type": "^1.2.5",
"flagpack": "^1.0.5",
"frappe-charts": "^1.5.6",
"frappe-charts": "^1.6.2",
"haversine-distance": "^1.2.1",
"maidenhead": "^1.0.7",
"mapbox-gl": "^1.13.1",
"moment": "^2.29.1",
"moment": "^2.29.4",
"node-vincenty": "0.0.6",
"photoswipe": "^4.1.3",
"proj4": "^2.7.2",
"togpx": "^0.5.4",
"vue": "^2.6.12",
"vue": "^2.7.14",
"vue-clipboard2": "^0.3.1",
"vue-debounce": "^2.6.0",
"vue-filepond": "^6.0.3",
"vue-infinite-loading": "^2.4.5",
"vue-lazy-youtube-video": "^2.3.0",
"vue-mapbox": "github:manuelkasper/vue-mapbox#fix-layer-remove",
"vue-mapbox": "github:manuelkasper/vue-mapbox#10cb772",
"vue-match-media": "^1.0.3",
"vue-native-websocket": "^2.0.14",
"vue-router": "^3.5.1",
"vue-native-websocket": "github:nathantsoi/vue-native-websocket#a265da6",
"vue-router": "^3.6.5",
"vuedraggable": "^2.24.3",
"vuex": "^3.6.2"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.12.1",
"@vue/cli-plugin-eslint": "^3.12.1",
"@vue/cli-service": "^3.12.1",
"@babel/eslint-parser": "^7.24.1",
"@vue/cli-plugin-babel": "^5.0.8",
"@vue/cli-plugin-eslint": "^5.0.8",
"@vue/cli-service": "^5.0.8",
"@vue/eslint-config-standard": "^4.0.0",
"babel-eslint": "^10.1.0",
"eslint": "^5.16.0",
"eslint-plugin-vue": "^5.2.3",
"git-revision-webpack-plugin": "^3.0.6",
"node-sass": "^4.14.1",
"sass-loader": "^7.3.1",
"eslint": "^8.57.0",
"eslint-plugin-vue": "^9.24.0",
"git-revision-webpack-plugin": "^5.0.0",
"node-sass": "^9.0.0",
"sass": "^1.75.0",
"sass-loader": "^14.2.1",
"vue-svgicon": "^3.2.9",
"vue-template-compiler": "^2.6.12"
"vue-template-compiler": "^2.7.14"
},
"eslintConfig": {
"root": true,
@ -73,9 +75,13 @@
"plugin:vue/essential",
"@vue/standard"
],
"rules": {},
"rules": {
"vue/multi-word-component-names": "off",
"vue/no-reserved-component-names": "off",
"vue/no-unused-vars": "off"
},
"parserOptions": {
"parser": "babel-eslint"
"parser": "@babel/eslint-parser"
},
"globals": {
"VERSION": true,

Wyświetl plik

@ -16,13 +16,13 @@ export default {
</script>
<style lang="scss">
@import "~bulma/sass/utilities/_all";
@import "bulma/sass/utilities/_all";
$link: $blue;
@import "~bulma";
@import "~buefy/src/scss/buefy";
@import "~flagpack/dist/flagpack.css";
@import '~mapbox-gl/dist/mapbox-gl.css';
@import '~@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css'
@import "bulma";
@import "buefy/src/scss/buefy";
@import "flagpack/dist/flagpack.css";
@import '@maptiler/sdk/dist/maptiler-sdk.css';
@import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css';
</style>

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 58 KiB

Wyświetl plik

@ -0,0 +1,420 @@
{
"version": 8,
"name": "basemapat",
"center": [13.1411895, 47.698321],
"zoom": 6,
"bearing": 0,
"pitch": 0,
"sources": {
"basemapat": {
"type": "raster",
"tiles": [
"https://mapsneu.wien.gv.at/basemap/bmapgrau/normal/google3857/{z}/{y}/{x}.png"
],
"tileSize": 256,
"maxzoom": 19,
"bounds": [8.782379, 46.358770, 17.5, 49.037872],
"attribution": "Grundkarte: <a target=\"_blank\" href=\"https://basemap.at/\">basemap.at</a>"
},
"summits": {
"type": "vector",
"url": "https://api.maptiler.com/tiles/d6ccc3ec-a677-4fcd-a211-2f2da36965cb/tiles.json?key={key}"
},
"summits_inactive": {
"type": "vector",
"url": "https://api.maptiler.com/tiles/ac4e1bc3-fbfb-4830-8279-675cc18f86f0/tiles.json?key={key}"
},
"regions": {
"type": "vector",
"url": "https://api.maptiler.com/tiles/2d324268-fe52-4875-96ca-bc5692fc1225/tiles.json?key={key}"
},
"az": {
"type": "vector",
"url": "https://api.maptiler.com/tiles/e3f0b69a-1a14-4a8c-933a-4c4e134fdaa3/tiles.json?key={key}"
},
"v3": {
"url": "https://api.maptiler.com/tiles/v3/tiles.json?key={key}",
"type": "vector",
"maxzoom": 10
}
},
"sprite": "https://sotl.as/sprites",
"glyphs": "https://api.maptiler.com/fonts/{fontstack}/{range}.pbf?key={key}",
"transition": {},
"layers": [
{
"id": "background",
"type": "background",
"layout": {"visibility": "visible"},
"paint": {"background-color": "rgba(255, 255, 255, 1)"}
},
{
"id": "background_water",
"type": "fill",
"source": "v3",
"source-layer": "water",
"layout": {
"visibility": "visible"
},
"paint": {
"fill-color": "rgba(103, 166, 196, 0.2)"
},
"filter": [
"==",
"$type",
"Polygon"
]
},
{
"id": "background_boundary",
"type": "line",
"source": "v3",
"source-layer": "boundary",
"layout": {
"line-cap": "round",
"line-join": "round",
"visibility": "visible"
},
"paint": {
"line-color": "rgba(136, 136, 136, 1)",
"line-width": {
"base": 1,
"stops": [
[
3,
1
],
[
5,
1.2
],
[
12,
3
]
]
},
"line-opacity": 0.2
},
"filter": [
"all",
[
"==",
"admin_level",
2
],
[
"==",
"maritime",
0
]
]
},
{
"id": "basemapat",
"type": "raster",
"source": "basemapat",
"layout": {"visibility": "visible"},
"paint": {
"raster-opacity": 0.75,
"raster-resampling": "linear"
}
},
{
"id": "summits_az",
"type": "fill",
"metadata": {
"sotlas-map-option": "az"
},
"source": "az",
"source-layer": "az",
"layout": {"visibility": "none"},
"minzoom": 12,
"paint": {
"fill-antialias": false,
"fill-color": "rgba(50, 255, 0, 0.4)",
"fill-opacity": {"stops": [[12, 0], [12.5, 0.5]]}
}
},
{
"id": "summits_az_border",
"type": "line",
"metadata": {
"sotlas-map-option": "az"
},
"source": "az",
"source-layer": "az",
"layout": {"visibility": "none"},
"minzoom": 12,
"paint": {
"line-color": "rgba(50, 150, 0, 1)",
"line-opacity": {"stops": [[12, 0], [12.5, 0.5]]},
"line-width": {"stops": [[12, 1], [16, 2]]},
"line-dasharray": [1,1]
}
},
{
"id": "summits_selected",
"type": "circle",
"source": "summits",
"source-layer": "summits",
"filter": ["all", ["in", "code"]],
"layout": {"visibility": "visible"},
"paint": {
"circle-color": "rgba(2, 153, 243, 1)",
"circle-radius": {"stops": [[6, 15], [20, 50]]},
"circle-opacity": 0.75,
"circle-stroke-color": "rgba(210, 255, 0, 0.05)",
"circle-stroke-width": 0,
"circle-stroke-opacity": 1,
"circle-blur": 0.7
}
},
{
"id": "summits_names",
"type": "symbol",
"source": "summits",
"source-layer": "summits",
"minzoom": 10,
"maxzoom": 24,
"filter": ["all", ["in", "code"]],
"layout": {
"visibility": "visible",
"text-field": "{name}\n{code}\n{alt} m",
"text-size": {"stops": [[10, 10], [20, 16]]},
"text-font": ["Noto Sans Regular"],
"text-anchor": "bottom",
"text-offset": {"stops": [[10, [0, -1]], [20, [0, -2]]]},
"icon-size": 1,
"symbol-spacing": 250,
"symbol-avoid-edges": false,
"text-keep-upright": true,
"text-transform": "none",
"text-optional": false,
"text-allow-overlap": {"stops": [[18, false], [19, true]]},
"text-ignore-placement": false,
"text-justify": "center",
"text-rotate": 0
},
"paint": {
"text-color": "rgba(51, 51, 51, 1)",
"text-halo-color": "rgba(255, 255, 255, 1)",
"text-halo-width": 1,
"text-halo-blur": 1
}
},
{
"id": "summits_circles_all",
"type": "circle",
"source": "summits",
"source-layer": "summits",
"layout": {"visibility": "none"},
"paint": {
"circle-stroke-color": "rgba(255, 255, 255, 1)",
"circle-color": [
"match",
["get", "points"],
[1],
"rgba(77, 122, 32, 0.5)",
[2],
"rgba(109, 165, 54, 0.5)",
[4],
"rgba(174, 167, 39, 0.5)",
[6],
"rgba(239, 168, 24, 0.5)",
[8],
"rgba(220, 93, 4, 0.5)",
[10],
"rgba(200, 16, 30, 0.5)",
"#000"
],
"circle-stroke-width": {"stops": [[4, 0], [15, 1]]},
"circle-radius": {"stops": [[0, 0.05], [10, 2.5], [22, 12]]}
}
},
{
"id": "summits_circles",
"type": "circle",
"source": "summits",
"source-layer": "summits",
"filter": ["all", ["in", "code"]],
"layout": {"visibility": "visible"},
"paint": {
"circle-stroke-color": "rgba(255, 255, 255, 1)",
"circle-color": [
"match",
["get", "points"],
[1],
"rgba(77, 122, 32, 1)",
[2],
"rgba(109, 165, 54, 1)",
[4],
"rgba(174, 167, 39, 1)",
[6],
"rgba(239, 168, 24, 1)",
[8],
"rgba(220, 93, 4, 1)",
[10],
"rgba(200, 16, 30, 1)",
"#000"
],
"circle-stroke-width": {"stops": [[4, 0], [15, 2]]},
"circle-radius": {"stops": [[0, 0.1], [10, 8], [22, 20]]}
}
},
{
"id": "summits_activations",
"type": "symbol",
"source": "summits",
"source-layer": "summits",
"minzoom": 10,
"maxzoom": 24,
"filter": ["all", ["in", "code"]],
"layout": {
"text-field": "{act}",
"text-font": ["Noto Sans Bold"],
"text-size": {"stops": [[10, 8], [20, 16]]},
"text-offset": [0,0.1]
},
"paint": {"text-color": "rgba(255, 255, 255, 1)"}
},
{
"id": "summits_highlight",
"type": "circle",
"source": "summits",
"source-layer": "summits",
"filter": ["all", ["in", "code"]],
"layout": {"visibility": "visible"},
"paint": {
"circle-color": "rgba(2, 243, 198, 1)",
"circle-radius": {"stops": [[6, 15], [20, 50]]},
"circle-opacity": 0.75,
"circle-blur": 0.7
}
},
{
"id": "summits_highlight_alerts",
"type": "circle",
"source": "summits",
"source-layer": "summits",
"filter": ["all", ["in", "code"]],
"layout": {"visibility": "visible"},
"paint": {
"circle-color": "rgba(210, 255, 0, 1)",
"circle-radius": {"stops": [[6, 15], [20, 50]]},
"circle-opacity": 0.55,
"circle-blur": 0.7
}
},
{
"id": "summits_inactive_names",
"type": "symbol",
"metadata": {
"sotlas-map-option": "inactive"
},
"source": "summits_inactive",
"source-layer": "summits_inactive",
"minzoom": 10,
"maxzoom": 24,
"filter": ["all", ["in", "code"]],
"layout": {
"visibility": "none",
"text-field": "{name}\n{code}\n{alt} m\n(inactive)",
"text-size": {"stops": [[10, 10], [20, 16]]},
"text-font": ["Noto Sans Regular"],
"text-anchor": "bottom",
"text-offset": {"stops": [[10, [0, -1]], [20, [0, -2]]]},
"icon-size": 1,
"symbol-spacing": 250,
"symbol-avoid-edges": false,
"text-keep-upright": true,
"text-transform": "none",
"text-optional": false,
"text-allow-overlap": {"stops": [[18, false], [19, true]]},
"text-ignore-placement": false,
"text-justify": "center",
"text-rotate": 0
},
"paint": {
"text-color": "rgba(51, 51, 51, 1)",
"text-halo-color": "rgba(255, 255, 255, 1)",
"text-halo-width": 1,
"text-halo-blur": 1,
"text-opacity": 1
}
},
{
"id": "summits_inactive_circles",
"type": "circle",
"metadata": {
"sotlas-map-option": "inactive"
},
"source": "summits_inactive",
"source-layer": "summits_inactive",
"filter": ["all", ["in", "code"]],
"layout": {"visibility": "none"},
"paint": {
"circle-stroke-color": "rgba(255, 255, 255, 1)",
"circle-color": [
"match",
["get", "points"],
[1],
"rgba(77, 122, 32, 0.5)",
[2],
"rgba(109, 165, 54, 0.5)",
[4],
"rgba(174, 167, 39, 0.5)",
[6],
"rgba(239, 168, 24, 0.5)",
[8],
"rgba(220, 93, 4, 0.5)",
[10],
"rgba(200, 16, 30, 0.5)",
"#000"
],
"circle-stroke-width": {"stops": [[4, 0], [15, 2]]},
"circle-radius": {"stops": [[0, 0.1], [10, 8], [22, 20]]}
}
},
{
"id": "regions_areas",
"type": "fill",
"metadata": {
"sotlas-map-option": "regions"
},
"source": "regions",
"source-layer": "areas",
"minzoom": 0,
"layout": {"visibility": "none"},
"paint": {
"fill-opacity": 0.1,
"fill-antialias": false,
"fill-color": "rgba(0, 0, 0, 1)"
}
},
{
"id": "regions_labels",
"type": "symbol",
"metadata": {
"sotlas-map-option": "regions"
},
"source": "regions",
"source-layer": "labels",
"layout": {
"visibility": "none",
"text-field": "{region}",
"text-anchor": "top-left",
"text-justify": "center",
"text-offset": [0.3, 0.3],
"text-font": ["Noto Sans Regular"],
"text-size": {"stops": [[6, 8], [10, 16]]}
},
"paint": {
"text-halo-color": "rgba(255, 255, 255, 1)",
"text-halo-width": 0.5,
"text-halo-blur": 1,
"text-translate": [0, 0]
}
}
]
}

Wyświetl plik

@ -0,0 +1,419 @@
{
"version": 8,
"name": "caltopo",
"center": [-110.0, 47.0],
"zoom": 2.5,
"bearing": 0,
"pitch": 0,
"sources": {
"caltopo": {
"type": "raster",
"tiles": [
"https://s3-us-west-1.amazonaws.com/caltopo/topo/{z}/{x}/{y}.png"
],
"tileSize": 256,
"maxzoom": 16,
"bounds": [-175, 8, -45, 84],
"attribution": "© CalTopo"
},
"summits": {
"type": "vector",
"url": "https://api.maptiler.com/tiles/d6ccc3ec-a677-4fcd-a211-2f2da36965cb/tiles.json?key={key}"
},
"summits_inactive": {
"type": "vector",
"url": "https://api.maptiler.com/tiles/ac4e1bc3-fbfb-4830-8279-675cc18f86f0/tiles.json?key={key}"
},
"regions": {
"type": "vector",
"url": "https://api.maptiler.com/tiles/2d324268-fe52-4875-96ca-bc5692fc1225/tiles.json?key={key}"
},
"az": {
"type": "vector",
"url": "https://api.maptiler.com/tiles/e3f0b69a-1a14-4a8c-933a-4c4e134fdaa3/tiles.json?key={key}"
},
"v3": {
"url": "https://api.maptiler.com/tiles/v3/tiles.json?key={key}",
"type": "vector",
"maxzoom": 10
}
},
"sprite": "https://sotl.as/sprites",
"glyphs": "https://api.maptiler.com/fonts/{fontstack}/{range}.pbf?key={key}",
"transition": {},
"layers": [
{
"id": "background",
"type": "background",
"layout": {"visibility": "visible"},
"paint": {"background-color": "rgba(255, 255, 255, 1)"}
},
{
"id": "background_water",
"type": "fill",
"source": "v3",
"source-layer": "water",
"layout": {
"visibility": "visible"
},
"paint": {
"fill-color": "rgba(103, 166, 196, 0.2)"
},
"filter": [
"==",
"$type",
"Polygon"
]
},
{
"id": "background_boundary",
"type": "line",
"source": "v3",
"source-layer": "boundary",
"layout": {
"line-cap": "round",
"line-join": "round",
"visibility": "visible"
},
"paint": {
"line-color": "rgba(136, 136, 136, 1)",
"line-width": {
"base": 1,
"stops": [
[
3,
1
],
[
5,
1.2
],
[
12,
3
]
]
},
"line-opacity": 0.2
},
"filter": [
"all",
[
"==",
"admin_level",
2
],
[
"==",
"maritime",
0
]
]
},
{
"id": "caltopo",
"type": "raster",
"source": "caltopo",
"layout": {"visibility": "visible"},
"paint": {
"raster-opacity": 0.75,
"raster-resampling": "linear"
}
},
{
"id": "summits_az",
"type": "fill",
"metadata": {
"sotlas-map-option": "az"
},
"source": "az",
"source-layer": "az",
"layout": {"visibility": "none"},
"minzoom": 12,
"paint": {
"fill-antialias": false,
"fill-color": "rgba(255, 255, 0, 1)",
"fill-opacity": {"stops": [[12, 0], [12.5, 0.5]]}
}
},
{
"id": "summits_az_border",
"type": "line",
"metadata": {
"sotlas-map-option": "az"
},
"source": "az",
"source-layer": "az",
"layout": {"visibility": "none"},
"minzoom": 12,
"paint": {
"line-color": "rgba(235, 196, 0, 1)",
"line-opacity": {"stops": [[12, 0], [12.5, 0.5]]},
"line-width": {"stops": [[12, 1], [16, 3]]}
}
},
{
"id": "summits_selected",
"type": "circle",
"source": "summits",
"source-layer": "summits",
"filter": ["all", ["in", "code"]],
"layout": {"visibility": "visible"},
"paint": {
"circle-color": "rgba(2, 153, 243, 1)",
"circle-radius": {"stops": [[6, 15], [20, 50]]},
"circle-opacity": 0.75,
"circle-stroke-color": "rgba(210, 255, 0, 0.05)",
"circle-stroke-width": 0,
"circle-stroke-opacity": 1,
"circle-blur": 0.7
}
},
{
"id": "summits_names",
"type": "symbol",
"source": "summits",
"source-layer": "summits",
"minzoom": 10,
"maxzoom": 24,
"filter": ["all", ["in", "code"]],
"layout": {
"visibility": "visible",
"text-field": "{name}\n{code}\n{alt} m",
"text-size": {"stops": [[10, 10], [20, 16]]},
"text-font": ["Frutiger Neue Regular"],
"text-anchor": "bottom",
"text-offset": {"stops": [[10, [0, -1]], [20, [0, -2]]]},
"icon-size": 1,
"symbol-spacing": 250,
"symbol-avoid-edges": false,
"text-keep-upright": true,
"text-transform": "none",
"text-optional": false,
"text-allow-overlap": {"stops": [[18, false], [19, true]]},
"text-ignore-placement": false,
"text-justify": "center",
"text-rotate": 0
},
"paint": {
"text-color": "rgba(51, 51, 51, 1)",
"text-halo-color": "rgba(255, 255, 255, 1)",
"text-halo-width": 1,
"text-halo-blur": 1
}
},
{
"id": "summits_circles_all",
"type": "circle",
"source": "summits",
"source-layer": "summits",
"layout": {"visibility": "none"},
"paint": {
"circle-stroke-color": "rgba(255, 255, 255, 1)",
"circle-color": [
"match",
["get", "points"],
[1],
"rgba(77, 122, 32, 0.5)",
[2],
"rgba(109, 165, 54, 0.5)",
[4],
"rgba(174, 167, 39, 0.5)",
[6],
"rgba(239, 168, 24, 0.5)",
[8],
"rgba(220, 93, 4, 0.5)",
[10],
"rgba(200, 16, 30, 0.5)",
"#000"
],
"circle-stroke-width": {"stops": [[4, 0], [15, 1]]},
"circle-radius": {"stops": [[0, 0.05], [10, 2.5], [22, 12]]}
}
},
{
"id": "summits_circles",
"type": "circle",
"source": "summits",
"source-layer": "summits",
"filter": ["all", ["in", "code"]],
"layout": {"visibility": "visible"},
"paint": {
"circle-stroke-color": "rgba(255, 255, 255, 1)",
"circle-color": [
"match",
["get", "points"],
[1],
"rgba(77, 122, 32, 1)",
[2],
"rgba(109, 165, 54, 1)",
[4],
"rgba(174, 167, 39, 1)",
[6],
"rgba(239, 168, 24, 1)",
[8],
"rgba(220, 93, 4, 1)",
[10],
"rgba(200, 16, 30, 1)",
"#000"
],
"circle-stroke-width": {"stops": [[4, 0], [15, 2]]},
"circle-radius": {"stops": [[0, 0.1], [10, 8], [22, 20]]}
}
},
{
"id": "summits_activations",
"type": "symbol",
"source": "summits",
"source-layer": "summits",
"minzoom": 10,
"maxzoom": 24,
"filter": ["all", ["in", "code"]],
"layout": {
"text-field": "{act}",
"text-font": ["Frutiger Neue Bold"],
"text-size": {"stops": [[10, 8], [20, 16]]},
"text-offset": [0,0.1]
},
"paint": {"text-color": "rgba(255, 255, 255, 1)"}
},
{
"id": "summits_highlight",
"type": "circle",
"source": "summits",
"source-layer": "summits",
"filter": ["all", ["in", "code"]],
"layout": {"visibility": "visible"},
"paint": {
"circle-color": "rgba(2, 243, 198, 1)",
"circle-radius": {"stops": [[6, 15], [20, 50]]},
"circle-opacity": 0.75,
"circle-blur": 0.7
}
},
{
"id": "summits_highlight_alerts",
"type": "circle",
"source": "summits",
"source-layer": "summits",
"filter": ["all", ["in", "code"]],
"layout": {"visibility": "visible"},
"paint": {
"circle-color": "rgba(210, 255, 0, 1)",
"circle-radius": {"stops": [[6, 15], [20, 50]]},
"circle-opacity": 0.55,
"circle-blur": 0.7
}
},
{
"id": "summits_inactive_names",
"type": "symbol",
"metadata": {
"sotlas-map-option": "inactive"
},
"source": "summits_inactive",
"source-layer": "summits_inactive",
"minzoom": 10,
"maxzoom": 24,
"filter": ["all", ["in", "code"]],
"layout": {
"visibility": "none",
"text-field": "{name}\n{code}\n{alt} m\n(inactive)",
"text-size": {"stops": [[10, 10], [20, 16]]},
"text-font": ["Frutiger Neue Regular"],
"text-anchor": "bottom",
"text-offset": {"stops": [[10, [0, -1]], [20, [0, -2]]]},
"icon-size": 1,
"symbol-spacing": 250,
"symbol-avoid-edges": false,
"text-keep-upright": true,
"text-transform": "none",
"text-optional": false,
"text-allow-overlap": {"stops": [[18, false], [19, true]]},
"text-ignore-placement": false,
"text-justify": "center",
"text-rotate": 0
},
"paint": {
"text-color": "rgba(51, 51, 51, 1)",
"text-halo-color": "rgba(255, 255, 255, 1)",
"text-halo-width": 1,
"text-halo-blur": 1,
"text-opacity": 1
}
},
{
"id": "summits_inactive_circles",
"type": "circle",
"metadata": {
"sotlas-map-option": "inactive"
},
"source": "summits_inactive",
"source-layer": "summits_inactive",
"filter": ["all", ["in", "code"]],
"layout": {"visibility": "none"},
"paint": {
"circle-stroke-color": "rgba(255, 255, 255, 1)",
"circle-color": [
"match",
["get", "points"],
[1],
"rgba(77, 122, 32, 0.5)",
[2],
"rgba(109, 165, 54, 0.5)",
[4],
"rgba(174, 167, 39, 0.5)",
[6],
"rgba(239, 168, 24, 0.5)",
[8],
"rgba(220, 93, 4, 0.5)",
[10],
"rgba(200, 16, 30, 0.5)",
"#000"
],
"circle-stroke-width": {"stops": [[4, 0], [15, 2]]},
"circle-radius": {"stops": [[0, 0.1], [10, 8], [22, 20]]}
}
},
{
"id": "regions_areas",
"type": "fill",
"metadata": {
"sotlas-map-option": "regions"
},
"source": "regions",
"source-layer": "areas",
"minzoom": 0,
"layout": {"visibility": "none"},
"paint": {
"fill-opacity": 0.1,
"fill-antialias": false,
"fill-color": "rgba(0, 0, 0, 1)"
}
},
{
"id": "regions_labels",
"type": "symbol",
"metadata": {
"sotlas-map-option": "regions"
},
"source": "regions",
"source-layer": "labels",
"layout": {
"visibility": "none",
"text-field": "{region}",
"text-anchor": "top-left",
"text-justify": "center",
"text-offset": [0.3, 0.3],
"text-font": ["Frutiger Neue Regular"],
"text-size": {"stops": [[6, 8], [10, 16]]}
},
"paint": {
"text-halo-color": "rgba(255, 255, 255, 1)",
"text-halo-width": 0.5,
"text-halo-blur": 1,
"text-translate": [0, 0]
}
}
]
}

Wyświetl plik

@ -148,10 +148,14 @@ hr {
}
/* Fix for scale text selection */
.mapboxgl-ctrl-scale {
.maplibregl-ctrl-scale {
user-select: none;
}
.maplibregl-popup-content {
padding-top: 10px;
}
/* Fix Buefy bug */
@media screen and (max-width: 1023px) {
.dropdown.is-mobile-modal>.dropdown-menu>.dropdown-content>div>a {

Wyświetl plik

@ -0,0 +1,419 @@
{
"version": 8,
"name": "norkart",
"center": [15.956668, 65.400009],
"zoom": 4,
"bearing": 0,
"pitch": 0,
"sources": {
"norkart": {
"type": "raster",
"tiles": [
"https://opencache.statkart.no/gatekeeper/gk/gk.open_gmaps?layers=topo4&zoom={z}&x={x}&y={y}"
],
"tileSize": 256,
"maxzoom": 20,
"bounds": [2, 57, 33, 72],
"attribution": "© Kartverket"
},
"summits": {
"type": "vector",
"url": "https://api.maptiler.com/tiles/d6ccc3ec-a677-4fcd-a211-2f2da36965cb/tiles.json?key={key}"
},
"summits_inactive": {
"type": "vector",
"url": "https://api.maptiler.com/tiles/ac4e1bc3-fbfb-4830-8279-675cc18f86f0/tiles.json?key={key}"
},
"regions": {
"type": "vector",
"url": "https://api.maptiler.com/tiles/2d324268-fe52-4875-96ca-bc5692fc1225/tiles.json?key={key}"
},
"az": {
"type": "vector",
"url": "https://api.maptiler.com/tiles/e3f0b69a-1a14-4a8c-933a-4c4e134fdaa3/tiles.json?key={key}"
},
"v3": {
"url": "https://api.maptiler.com/tiles/v3/tiles.json?key={key}",
"type": "vector",
"maxzoom": 10
}
},
"sprite": "https://sotl.as/sprites",
"glyphs": "https://api.maptiler.com/fonts/{fontstack}/{range}.pbf?key={key}",
"transition": {},
"layers": [
{
"id": "background",
"type": "background",
"layout": {"visibility": "visible"},
"paint": {"background-color": "rgba(255, 255, 255, 1)"}
},
{
"id": "background_water",
"type": "fill",
"source": "v3",
"source-layer": "water",
"layout": {
"visibility": "visible"
},
"paint": {
"fill-color": "rgba(103, 166, 196, 0.2)"
},
"filter": [
"==",
"$type",
"Polygon"
]
},
{
"id": "background_boundary",
"type": "line",
"source": "v3",
"source-layer": "boundary",
"layout": {
"line-cap": "round",
"line-join": "round",
"visibility": "visible"
},
"paint": {
"line-color": "rgba(136, 136, 136, 1)",
"line-width": {
"base": 1,
"stops": [
[
3,
1
],
[
5,
1.2
],
[
12,
3
]
]
},
"line-opacity": 0.2
},
"filter": [
"all",
[
"==",
"admin_level",
2
],
[
"==",
"maritime",
0
]
]
},
{
"id": "norkart",
"type": "raster",
"source": "norkart",
"layout": {"visibility": "visible"},
"paint": {
"raster-opacity": 0.75,
"raster-resampling": "linear"
}
},
{
"id": "summits_az",
"type": "fill",
"metadata": {
"sotlas-map-option": "az"
},
"source": "az",
"source-layer": "az",
"layout": {"visibility": "none"},
"minzoom": 12,
"paint": {
"fill-antialias": false,
"fill-color": "rgba(255, 255, 0, 1)",
"fill-opacity": {"stops": [[12, 0], [12.5, 0.5]]}
}
},
{
"id": "summits_az_border",
"type": "line",
"metadata": {
"sotlas-map-option": "az"
},
"source": "az",
"source-layer": "az",
"layout": {"visibility": "none"},
"minzoom": 12,
"paint": {
"line-color": "rgba(235, 196, 0, 1)",
"line-opacity": {"stops": [[12, 0], [12.5, 0.5]]},
"line-width": {"stops": [[12, 1], [16, 3]]}
}
},
{
"id": "summits_selected",
"type": "circle",
"source": "summits",
"source-layer": "summits",
"filter": ["all", ["in", "code"]],
"layout": {"visibility": "visible"},
"paint": {
"circle-color": "rgba(2, 153, 243, 1)",
"circle-radius": {"stops": [[6, 15], [20, 50]]},
"circle-opacity": 0.75,
"circle-stroke-color": "rgba(210, 255, 0, 0.05)",
"circle-stroke-width": 0,
"circle-stroke-opacity": 1,
"circle-blur": 0.7
}
},
{
"id": "summits_names",
"type": "symbol",
"source": "summits",
"source-layer": "summits",
"minzoom": 10,
"maxzoom": 24,
"filter": ["all", ["in", "code"]],
"layout": {
"visibility": "visible",
"text-field": "{name}\n{code}\n{alt} m",
"text-size": {"stops": [[10, 10], [20, 16]]},
"text-font": ["Frutiger Neue Regular"],
"text-anchor": "bottom",
"text-offset": {"stops": [[10, [0, -1]], [20, [0, -2]]]},
"icon-size": 1,
"symbol-spacing": 250,
"symbol-avoid-edges": false,
"text-keep-upright": true,
"text-transform": "none",
"text-optional": false,
"text-allow-overlap": {"stops": [[18, false], [19, true]]},
"text-ignore-placement": false,
"text-justify": "center",
"text-rotate": 0
},
"paint": {
"text-color": "rgba(51, 51, 51, 1)",
"text-halo-color": "rgba(255, 255, 255, 1)",
"text-halo-width": 1,
"text-halo-blur": 1
}
},
{
"id": "summits_circles_all",
"type": "circle",
"source": "summits",
"source-layer": "summits",
"layout": {"visibility": "none"},
"paint": {
"circle-stroke-color": "rgba(255, 255, 255, 1)",
"circle-color": [
"match",
["get", "points"],
[1],
"rgba(77, 122, 32, 0.5)",
[2],
"rgba(109, 165, 54, 0.5)",
[4],
"rgba(174, 167, 39, 0.5)",
[6],
"rgba(239, 168, 24, 0.5)",
[8],
"rgba(220, 93, 4, 0.5)",
[10],
"rgba(200, 16, 30, 0.5)",
"#000"
],
"circle-stroke-width": {"stops": [[4, 0], [15, 1]]},
"circle-radius": {"stops": [[0, 0.05], [10, 2.5], [22, 12]]}
}
},
{
"id": "summits_circles",
"type": "circle",
"source": "summits",
"source-layer": "summits",
"filter": ["all", ["in", "code"]],
"layout": {"visibility": "visible"},
"paint": {
"circle-stroke-color": "rgba(255, 255, 255, 1)",
"circle-color": [
"match",
["get", "points"],
[1],
"rgba(77, 122, 32, 1)",
[2],
"rgba(109, 165, 54, 1)",
[4],
"rgba(174, 167, 39, 1)",
[6],
"rgba(239, 168, 24, 1)",
[8],
"rgba(220, 93, 4, 1)",
[10],
"rgba(200, 16, 30, 1)",
"#000"
],
"circle-stroke-width": {"stops": [[4, 0], [15, 2]]},
"circle-radius": {"stops": [[0, 0.1], [10, 8], [22, 20]]}
}
},
{
"id": "summits_activations",
"type": "symbol",
"source": "summits",
"source-layer": "summits",
"minzoom": 10,
"maxzoom": 24,
"filter": ["all", ["in", "code"]],
"layout": {
"text-field": "{act}",
"text-font": ["Frutiger Neue Bold"],
"text-size": {"stops": [[10, 8], [20, 16]]},
"text-offset": [0,0.1]
},
"paint": {"text-color": "rgba(255, 255, 255, 1)"}
},
{
"id": "summits_highlight",
"type": "circle",
"source": "summits",
"source-layer": "summits",
"filter": ["all", ["in", "code"]],
"layout": {"visibility": "visible"},
"paint": {
"circle-color": "rgba(2, 243, 198, 1)",
"circle-radius": {"stops": [[6, 15], [20, 50]]},
"circle-opacity": 0.75,
"circle-blur": 0.7
}
},
{
"id": "summits_highlight_alerts",
"type": "circle",
"source": "summits",
"source-layer": "summits",
"filter": ["all", ["in", "code"]],
"layout": {"visibility": "visible"},
"paint": {
"circle-color": "rgba(210, 255, 0, 1)",
"circle-radius": {"stops": [[6, 15], [20, 50]]},
"circle-opacity": 0.55,
"circle-blur": 0.7
}
},
{
"id": "summits_inactive_names",
"type": "symbol",
"metadata": {
"sotlas-map-option": "inactive"
},
"source": "summits_inactive",
"source-layer": "summits_inactive",
"minzoom": 10,
"maxzoom": 24,
"filter": ["all", ["in", "code"]],
"layout": {
"visibility": "none",
"text-field": "{name}\n{code}\n{alt} m\n(inactive)",
"text-size": {"stops": [[10, 10], [20, 16]]},
"text-font": ["Frutiger Neue Regular"],
"text-anchor": "bottom",
"text-offset": {"stops": [[10, [0, -1]], [20, [0, -2]]]},
"icon-size": 1,
"symbol-spacing": 250,
"symbol-avoid-edges": false,
"text-keep-upright": true,
"text-transform": "none",
"text-optional": false,
"text-allow-overlap": {"stops": [[18, false], [19, true]]},
"text-ignore-placement": false,
"text-justify": "center",
"text-rotate": 0
},
"paint": {
"text-color": "rgba(51, 51, 51, 1)",
"text-halo-color": "rgba(255, 255, 255, 1)",
"text-halo-width": 1,
"text-halo-blur": 1,
"text-opacity": 1
}
},
{
"id": "summits_inactive_circles",
"type": "circle",
"metadata": {
"sotlas-map-option": "inactive"
},
"source": "summits_inactive",
"source-layer": "summits_inactive",
"filter": ["all", ["in", "code"]],
"layout": {"visibility": "none"},
"paint": {
"circle-stroke-color": "rgba(255, 255, 255, 1)",
"circle-color": [
"match",
["get", "points"],
[1],
"rgba(77, 122, 32, 0.5)",
[2],
"rgba(109, 165, 54, 0.5)",
[4],
"rgba(174, 167, 39, 0.5)",
[6],
"rgba(239, 168, 24, 0.5)",
[8],
"rgba(220, 93, 4, 0.5)",
[10],
"rgba(200, 16, 30, 0.5)",
"#000"
],
"circle-stroke-width": {"stops": [[4, 0], [15, 2]]},
"circle-radius": {"stops": [[0, 0.1], [10, 8], [22, 20]]}
}
},
{
"id": "regions_areas",
"type": "fill",
"metadata": {
"sotlas-map-option": "regions"
},
"source": "regions",
"source-layer": "areas",
"minzoom": 0,
"layout": {"visibility": "none"},
"paint": {
"fill-opacity": 0.1,
"fill-antialias": false,
"fill-color": "rgba(0, 0, 0, 1)"
}
},
{
"id": "regions_labels",
"type": "symbol",
"metadata": {
"sotlas-map-option": "regions"
},
"source": "regions",
"source-layer": "labels",
"layout": {
"visibility": "none",
"text-field": "{region}",
"text-anchor": "top-left",
"text-justify": "center",
"text-offset": [0.3, 0.3],
"text-font": ["Frutiger Neue Regular"],
"text-size": {"stops": [[6, 8], [10, 16]]}
},
"paint": {
"text-halo-color": "rgba(255, 255, 255, 1)",
"text-halo-width": 0.5,
"text-halo-blur": 1,
"text-translate": [0, 0]
}
}
]
}

Wyświetl plik

@ -0,0 +1 @@
<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" width="292" height="227" viewBox="0 0 292 227" xmlns="http://www.w3.org/2000/svg"><g fill="#29bdfe" fill-rule="nonzero"><path d="m0 43.287v175.006c0 5.721 5.776 9.632 11.087 7.51l69.766-31.755v-194.048l-70.686 28.273c-6.126 2.451-10.166 8.415-10.167 15.014z"/><path d="m97.024 194.048 97.024 32.341v-194.048l-97.024-32.341z"/><path d="m279.984.586-69.766 31.755v194.048l70.686-28.273c6.128-2.45 10.167-8.415 10.168-15.014v-175.007c0-5.72-5.776-9.631-11.088-7.509z"/></g></svg>

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 567 B

Wyświetl plik

@ -1,124 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="120.58959mm"
height="19.343578mm"
viewBox="0 0 120.58959 19.343578"
version="1.1"
id="svg8"
inkscape:version="0.92.2 5c3e80d, 2017-08-06"
sodipodi:docname="sotlas.svg">
<defs
id="defs2">
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath5259">
<use
x="0"
y="0"
xlink:href="#g5255"
id="use5261"
width="100%"
height="100%" />
</clipPath>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4"
inkscape:cx="185.55186"
inkscape:cy="66.811867"
inkscape:document-units="mm"
inkscape:current-layer="text12"
showgrid="false"
inkscape:window-width="2560"
inkscape:window-height="1329"
inkscape:window-x="0"
inkscape:window-y="1"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-78.247876,-11.392425)">
<g
aria-label="SOTLAS"
style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0.63764584px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
id="text12">
<path
d="m 120.40386,17.005825 q -0.0508,-1.1684 -0.508,-2.032 -0.4318,-0.8636 -1.1938,-1.4478 -0.762,-0.5842 -1.8288,-0.8636 -1.0414,-0.3048 -2.286,-0.3048 -0.762,0 -1.651,0.1778 -0.8636,0.1778 -1.6256,0.635 -0.7366,0.4318 -1.2192,1.1938 -0.4826,0.7366 -0.4826,1.8542 0,1.0922 0.5334,1.778 0.5334,0.6858 1.397,1.1176 0.8636,0.4064 1.9812,0.6604 1.1176,0.254 2.2606,0.4826 1.1684,0.2286 2.2606,0.5588 1.1176,0.3048 1.9812,0.8636 0.889,0.5334 1.4224,1.4224 0.5334,0.8636 0.5334,2.1844 0,1.4224 -0.6096,2.3876 -0.6096,0.9652 -1.5494,1.5748 -0.9144,0.6096 -2.0574,0.8636 -1.1176,0.2794 -2.159,0.2794 -1.6002,0 -2.9972,-0.3556 -1.397,-0.3302 -2.4384,-1.0922 -1.0414,-0.7874 -1.651,-2.0066 -0.5842,-1.2192 -0.5588,-2.9718 h 1.1176 q -0.0762,1.4986 0.4318,2.54 0.508,1.016 1.397,1.6764 0.9144,0.6604 2.1336,0.9652 1.2192,0.2794 2.5654,0.2794 0.8128,0 1.7272,-0.2032 0.9398,-0.2032 1.7018,-0.6858 0.7874,-0.4826 1.2954,-1.27 0.5334,-0.7874 0.5334,-1.9812 0,-1.143 -0.5334,-1.8542 -0.5334,-0.7366 -1.4224,-1.1684 -0.8636,-0.4572 -1.9812,-0.7112 -1.0922,-0.2794 -2.2606,-0.508 -1.143,-0.2286 -2.2606,-0.5334 -1.1176,-0.3048 -1.9812,-0.8128 -0.8636,-0.5334 -1.397,-1.3462 -0.5334,-0.8382 -0.5334,-2.1336 0,-1.2954 0.5334,-2.2098 0.5588,-0.9398 1.4224,-1.4986 0.889,-0.5842 1.9812,-0.8382 1.0922,-0.2794 2.159,-0.2794 1.4224,0 2.6416,0.3302 1.2446,0.3048 2.159,0.9906 0.9398,0.6604 1.4986,1.7272 0.5588,1.0668 0.635,2.5654 z"
style="fill:#29bdfe;fill-opacity:1"
id="path873"
inkscape:connector-curvature="0" />
<path
d="m 141.02509,20.892025 q 0,1.9812 -0.5842,3.7338 -0.5842,1.7272 -1.7018,3.0226 -1.0922,1.27 -2.6924,2.0066 -1.6002,0.7366 -3.6322,0.7366 -2.032,0 -3.6576,-0.7366 -1.6002,-0.7366 -2.7178,-2.0066 -1.0922,-1.2954 -1.6764,-3.0226 -0.5842,-1.7526 -0.5842,-3.7338 0,-1.9812 0.5842,-3.7084 0.5842,-1.7526 1.6764,-3.0226 1.1176,-1.2954 2.7178,-2.032 1.6256,-0.7366 3.6576,-0.7366 2.032,0 3.6322,0.7366 1.6002,0.7366 2.6924,2.032 1.1176,1.27 1.7018,3.0226 0.5842,1.7272 0.5842,3.7084 z m -16.129,0 q 0,1.7526 0.508,3.302 0.508,1.5494 1.4732,2.7178 0.9652,1.143 2.3622,1.8288 1.397,0.6858 3.175,0.6858 1.778,0 3.1496,-0.6858 1.397,-0.6858 2.3622,-1.8288 0.9652,-1.1684 1.4732,-2.7178 0.508,-1.5494 0.508,-3.302 0,-1.7526 -0.508,-3.302 -0.508,-1.5494 -1.4732,-2.6924 -0.9652,-1.1684 -2.3622,-1.8542 -1.3716,-0.6858 -3.1496,-0.6858 -1.778,0 -3.175,0.6858 -1.397,0.6858 -2.3622,1.8542 -0.9652,1.143 -1.4732,2.6924 -0.508,1.5494 -0.508,3.302 z"
style="fill:#29bdfe;fill-opacity:1"
id="path875"
inkscape:connector-curvature="0" />
<path
d="m 140.42045,12.789425 v -0.9652 h 13.8938 v 0.9652 h -6.4008 v 17.1704 h -1.1176 v -17.1704 z"
style="fill:#29bdfe;fill-opacity:1"
id="path877"
inkscape:connector-curvature="0" />
<path
d="m 155.59715,11.824225 h 1.1176 v 17.1704 h 10.287 v 0.9652 h -11.4046 z"
style="letter-spacing:2.04787493px;fill:#016490;fill-opacity:1"
id="path879"
inkscape:connector-curvature="0" />
<path
d="m 175.72983,11.824225 h 1.2192 l 7.1628,18.1356 h -1.1938 l -2.286,-5.8166 h -8.6868 l -2.3114,5.8166 h -1.1938 z m 4.5466,11.3538 -3.8862,-10.2616 h -0.0508 l -4.0386,10.2616 z"
style="fill:#29bdfe;fill-opacity:1"
id="path881"
inkscape:connector-curvature="0" />
<path
d="m 197.26267,17.005825 q -0.0508,-1.1684 -0.508,-2.032 -0.4318,-0.8636 -1.1938,-1.4478 -0.76199,-0.5842 -1.82879,-0.8636 -1.0414,-0.3048 -2.286,-0.3048 -0.762,0 -1.651,0.1778 -0.8636,0.1778 -1.6256,0.635 -0.7366,0.4318 -1.2192,1.1938 -0.4826,0.7366 -0.4826,1.8542 0,1.0922 0.5334,1.778 0.5334,0.6858 1.397,1.1176 0.8636,0.4064 1.9812,0.6604 1.1176,0.254 2.2606,0.4826 1.1684,0.2286 2.2606,0.5588 1.11759,0.3048 1.98119,0.8636 0.889,0.5334 1.4224,1.4224 0.5334,0.8636 0.5334,2.1844 0,1.4224 -0.6096,2.3876 -0.6096,0.9652 -1.5494,1.5748 -0.9144,0.6096 -2.05739,0.8636 -1.1176,0.2794 -2.159,0.2794 -1.6002,0 -2.9972,-0.3556 -1.397,-0.3302 -2.4384,-1.0922 -1.0414,-0.7874 -1.651,-2.0066 -0.5842,-1.2192 -0.5588,-2.9718 h 1.1176 q -0.0762,1.4986 0.4318,2.54 0.508,1.016 1.397,1.6764 0.9144,0.6604 2.1336,0.9652 1.2192,0.2794 2.5654,0.2794 0.8128,0 1.7272,-0.2032 0.93979,-0.2032 1.70179,-0.6858 0.7874,-0.4826 1.2954,-1.27 0.5334,-0.7874 0.5334,-1.9812 0,-1.143 -0.5334,-1.8542 -0.5334,-0.7366 -1.4224,-1.1684 -0.86359,-0.4572 -1.98119,-0.7112 -1.0922,-0.2794 -2.2606,-0.508 -1.143,-0.2286 -2.2606,-0.5334 -1.1176,-0.3048 -1.9812,-0.8128 -0.8636,-0.5334 -1.397,-1.3462 -0.5334,-0.8382 -0.5334,-2.1336 0,-1.2954 0.5334,-2.2098 0.5588,-0.9398 1.4224,-1.4986 0.889,-0.5842 1.9812,-0.8382 1.0922,-0.2794 2.159,-0.2794 1.4224,0 2.6416,0.3302 1.24459,0.3048 2.15899,0.9906 0.9398,0.6604 1.4986,1.7272 0.5588,1.0668 0.635,2.5654 z"
style="font-style:normal;font-variant:normal;font-weight:200;font-stretch:normal;font-size:25.39999962px;font-family:'Helvetica Neue';-inkscape-font-specification:'Helvetica Neue Ultra-Light';letter-spacing:0px;stroke-width:0.26458332;fill:#016490;fill-opacity:1"
id="path883"
inkscape:connector-curvature="0" />
<g
id="g5255"
inkscape:label="Clip">
<path
inkscape:connector-curvature="0"
style="fill:#29bdfe;fill-opacity:1;stroke-width:0.01132015"
d="M 78.247876,15.233355 V 30.05059 c 0,0.484324 0.48903,0.815479 0.938699,0.635783 l 5.906871,-2.688598 V 11.568408 l -5.98474,2.39381 a 1.3693707,1.3693707 0 0 0 -0.86083,1.271137 z"
id="path3324" />
<path
inkscape:connector-curvature="0"
style="fill:#29bdfe;fill-opacity:1;stroke-width:0.01132015"
d="m 86.46256,27.997775 8.214684,2.738229 V 14.306636 L 86.46256,11.568408 Z"
id="path3322" />
<path
inkscape:connector-curvature="0"
style="fill:#29bdfe;fill-opacity:1;stroke-width:0.01132015"
d="m 101.95323,11.618038 -5.906873,2.688598 v 16.429368 l 5.984743,-2.393811 a 1.3689428,1.3689428 0 0 0 0.86083,-1.271136 V 12.253821 c 0,-0.484324 -0.48903,-0.815479 -0.9387,-0.635783 z"
id="path2" />
</g>
</g>
</g>
</svg>
<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" width="1425" height="229" viewBox="0 0 1425 229" xmlns="http://www.w3.org/2000/svg"><g fill-rule="nonzero"><g fill="#29bdfe"><path d="m497.905 66.3c-.4-9.2-2.4-17.2-6-24-3.4-6.8-8.1-12.5-14.1-17.1s-13.2-8-21.6-10.2c-8.2-2.4-17.2-3.6-27-3.6-6 0-12.5.7-19.5 2.1-6.8 1.4-13.2 3.9-19.2 7.5-5.8 3.4-10.6 8.1-14.4 14.1-3.8 5.8-5.7 13.1-5.7 21.9 0 8.6 2.1 15.6 6.3 21s9.7 9.8 16.5 13.2c6.8 3.2 14.6 5.8 23.4 7.8s17.7 3.9 26.7 5.7c9.2 1.8 18.1 4 26.7 6.6 8.8 2.4 16.6 5.8 23.4 10.2 7 4.2 12.6 9.8 16.8 16.8 4.2 6.8 6.3 15.4 6.3 25.8 0 11.2-2.4 20.6-7.2 28.2s-10.9 13.8-18.3 18.6c-7.2 4.8-15.3 8.2-24.3 10.2-8.8 2.2-17.3 3.3-25.5 3.3-12.6 0-24.4-1.4-35.4-4.2-11-2.6-20.6-6.9-28.8-12.9-8.2-6.2-14.7-14.1-19.5-23.7-4.6-9.6-6.8-21.3-6.6-35.1h13.2c-.6 11.8 1.1 21.8 5.1 30 4 8 9.5 14.6 16.5 19.8 7.2 5.2 15.6 9 25.2 11.4 9.6 2.2 19.7 3.3 30.3 3.3 6.4 0 13.2-.8 20.4-2.4 7.4-1.6 14.1-4.3 20.1-8.1 6.2-3.8 11.3-8.8 15.3-15 4.2-6.2 6.3-14 6.3-23.4 0-9-2.1-16.3-6.3-21.9-4.2-5.8-9.8-10.4-16.8-13.8-6.8-3.6-14.6-6.4-23.4-8.4-8.6-2.2-17.5-4.2-26.7-6-9-1.8-17.9-3.9-26.7-6.3s-16.6-5.6-23.4-9.6c-6.8-4.2-12.3-9.5-16.5-15.9-4.2-6.6-6.3-15-6.3-25.2s2.1-18.9 6.3-26.1c4.4-7.4 10-13.3 16.8-17.7 7-4.6 14.8-7.9 23.4-9.9 8.6-2.2 17.1-3.3 25.5-3.3 11.2 0 21.6 1.3 31.2 3.9 9.8 2.4 18.3 6.3 25.5 11.7 7.4 5.2 13.3 12 17.7 20.4s6.9 18.5 7.5 30.3z"/><path d="m741.463 112.2c0 15.6-2.3 30.3-6.9 44.1-4.6 13.6-11.3 25.5-20.1 35.7-8.6 10-19.2 17.9-31.8 23.7s-26.9 8.7-42.9 8.7-30.4-2.9-43.2-8.7c-12.6-5.8-23.3-13.7-32.1-23.7-8.6-10.2-15.2-22.1-19.8-35.7-4.6-13.8-6.9-28.5-6.9-44.1s2.3-30.2 6.9-43.8c4.6-13.8 11.2-25.7 19.8-35.7 8.8-10.2 19.5-18.2 32.1-24 12.8-5.8 27.2-8.7 43.2-8.7s30.3 2.9 42.9 8.7 23.2 13.8 31.8 24c8.8 10 15.5 21.9 20.1 35.7 4.6 13.6 6.9 28.2 6.9 43.8zm-190.5 0c0 13.8 2 26.8 6 39s9.8 22.9 17.4 32.1c7.6 9 16.9 16.2 27.9 21.6s23.5 8.1 37.5 8.1 26.4-2.7 37.2-8.1c11-5.4 20.3-12.6 27.9-21.6 7.6-9.2 13.4-19.9 17.4-32.1s6-25.2 6-39-2-26.8-6-39-9.8-22.8-17.4-31.8c-7.6-9.2-16.9-16.5-27.9-21.9-10.8-5.4-23.2-8.1-37.2-8.1s-26.5 2.7-37.5 8.1-20.3 12.7-27.9 21.9c-7.6 9-13.4 19.6-17.4 31.8s-6 25.2-6 39z"/><path d="m734.322 16.5v-11.4h164.1v11.4h-75.6v202.8h-13.2v-202.8z"/></g><path d="m913.574 5.1h13.2v202.8h121.5v11.4h-134.7v-214.2z" fill="#016490"/><path d="m1151.36 5.1h14.4l84.6 214.2h-14.1l-27-68.7h-102.6l-27.3 68.7h-14.1l86.1-214.2zm53.7 134.1-45.9-121.2h-.6l-47.7 121.2z" fill="#29bdfe"/><path d="m1405.69 66.3c-.4-9.2-2.4-17.2-6-24-3.4-6.8-8.1-12.5-14.1-17.1s-13.2-8-21.6-10.2c-8.2-2.4-17.2-3.6-27-3.6-6 0-12.5.7-19.5 2.1-6.8 1.4-13.2 3.9-19.2 7.5-5.8 3.4-10.6 8.1-14.4 14.1-3.8 5.8-5.7 13.1-5.7 21.9 0 8.6 2.1 15.6 6.3 21s9.7 9.8 16.5 13.2c6.8 3.2 14.6 5.8 23.4 7.8s17.7 3.9 26.7 5.7c9.2 1.8 18.1 4 26.7 6.6 8.8 2.4 16.6 5.8 23.4 10.2 7 4.2 12.6 9.8 16.8 16.8 4.2 6.8 6.3 15.4 6.3 25.8 0 11.2-2.4 20.6-7.2 28.2s-10.9 13.8-18.3 18.6c-7.2 4.8-15.3 8.2-24.3 10.2-8.8 2.2-17.3 3.3-25.5 3.3-12.6 0-24.4-1.4-35.4-4.2-11-2.6-20.6-6.9-28.8-12.9-8.2-6.2-14.7-14.1-19.5-23.7-4.6-9.6-6.8-21.3-6.6-35.1h13.2c-.6 11.8 1.1 21.8 5.1 30 4 8 9.5 14.6 16.5 19.8 7.2 5.2 15.6 9 25.2 11.4 9.6 2.2 19.7 3.3 30.3 3.3 6.4 0 13.2-.8 20.4-2.4 7.4-1.6 14.1-4.3 20.1-8.1 6.2-3.8 11.3-8.8 15.3-15 4.2-6.2 6.3-14 6.3-23.4 0-9-2.1-16.3-6.3-21.9-4.2-5.8-9.8-10.4-16.8-13.8-6.8-3.6-14.6-6.4-23.4-8.4-8.6-2.2-17.5-4.2-26.7-6-9-1.8-17.9-3.9-26.7-6.3s-16.6-5.6-23.4-9.6c-6.8-4.2-12.3-9.5-16.5-15.9-4.2-6.6-6.3-15-6.3-25.2s2.1-18.9 6.3-26.1c4.4-7.4 10-13.3 16.8-17.7 7-4.6 14.8-7.9 23.4-9.9 8.6-2.2 17.1-3.3 25.5-3.3 11.2 0 21.6 1.3 31.2 3.9 9.8 2.4 18.3 6.3 25.5 11.7 7.4 5.2 13.3 12 17.7 20.4s6.9 18.5 7.5 30.3z" fill="#016490"/><path d="m0 45.365v175.007c0 5.72 5.776 9.632 11.087 7.509l69.766-31.755v-194.047l-70.686 28.273c-6.126 2.45-10.166 8.415-10.167 15.013z" fill="#29bdfe"/><path d="m97.024 196.126 97.024 32.341v-194.047l-97.024-32.341z" fill="#29bdfe"/><path d="m279.984 2.665-69.766 31.755v194.047l70.686-28.273c6.128-2.449 10.167-8.414 10.168-15.013v-175.007c0-5.72-5.776-9.632-11.088-7.509z" fill="#29bdfe"/></g></svg>

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 8.2 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 4.0 KiB

Plik diff jest za duży Load Diff

Wyświetl plik

@ -0,0 +1,552 @@
{
"version": 8,
"name": "swisstopo_aerial",
"center": [7.969664962869274, 47.021278030856564],
"zoom": 9.333879434342306,
"bearing": 0,
"pitch": 0,
"sources": {
"swisstopo": {
"type": "raster",
"tiles": [
"https://wmts.geo.admin.ch/1.0.0/ch.swisstopo.swissimage/default/current/3857/{z}/{x}/{y}.jpeg"
],
"tileSize": 256,
"maxzoom": 19,
"bounds": [5.140242, 45.398181, 11.47757, 48.230651],
"attribution": "© swisstopo"
},
"hiking_trails_raster": {
"type": "raster",
"tiles": [
"https://wmts.geo.admin.ch/1.0.0/ch.swisstopo.swisstlm3d-wanderwege/default/current/3857/{z}/{x}/{y}.png"
],
"tileSize": 256,
"maxzoom": 18,
"bounds": [5.140242, 45.398181, 11.47757, 48.230651]
},
"skiing_trails_raster": {
"type": "raster",
"tiles": [
"https://wmts.geo.admin.ch/1.0.0/ch.swisstopo-karto.skitouren/default/current/3857/{z}/{x}/{y}.png"
],
"tileSize": 256,
"maxzoom": 17,
"bounds": [5.140242, 45.398181, 11.47757, 48.230651]
},
"snowshoe_trails_raster": {
"type": "raster",
"tiles": [
"https://wmts.geo.admin.ch/1.0.0/ch.swisstopo-karto.schneeschuhrouten/default/current/3857/{z}/{x}/{y}.png"
],
"tileSize": 256,
"maxzoom": 17,
"bounds": [5.140242, 45.398181, 11.47757, 48.230651]
},
"wildlife_areas": {
"type": "raster",
"tiles": [
"https://wmts.geo.admin.ch/1.0.0/ch.bafu.wrz-wildruhezonen_portal/default/current/3857/{z}/{x}/{y}.png"
],
"tileSize": 256,
"maxzoom": 18,
"bounds": [5.140242, 45.398181, 11.47757, 48.230651]
},
"wildlife_reserves": {
"type": "raster",
"tiles": [
"https://wmts.geo.admin.ch/1.0.0/ch.bafu.wrz-jagdbanngebiete_select/default/current/3857/{z}/{x}/{y}.png"
],
"tileSize": 256,
"maxzoom": 18,
"bounds": [5.140242, 45.398181, 11.47757, 48.230651]
},
"slope_classes": {
"type": "raster",
"tiles": [
"https://wmts.geo.admin.ch/1.0.0/ch.swisstopo.hangneigung-ueber_30/default/current/3857/{z}/{x}/{y}.png"
],
"tileSize": 256,
"maxzoom": 14,
"bounds": [5.140242, 45.398181, 11.47757, 48.230651]
},
"summits": {
"type": "vector",
"url": "https://api.maptiler.com/tiles/d6ccc3ec-a677-4fcd-a211-2f2da36965cb/tiles.json?key={key}"
},
"summits_inactive": {
"type": "vector",
"url": "https://api.maptiler.com/tiles/ac4e1bc3-fbfb-4830-8279-675cc18f86f0/tiles.json?key={key}"
},
"regions": {
"type": "vector",
"url": "https://api.maptiler.com/tiles/2d324268-fe52-4875-96ca-bc5692fc1225/tiles.json?key={key}"
},
"az": {
"type": "vector",
"url": "https://api.maptiler.com/tiles/e3f0b69a-1a14-4a8c-933a-4c4e134fdaa3/tiles.json?key={key}"
},
"v3": {
"url": "https://api.maptiler.com/tiles/v3/tiles.json?key={key}",
"type": "vector",
"maxzoom": 10
}
},
"sprite": "https://vectortiles.geo.admin.ch/styles/ch.swisstopo.leichte-basiskarte.vt/sprite/sprite",
"glyphs": "https://vectortiles.geo.admin.ch/fonts/{fontstack}/{range}.pbf",
"transition": {},
"layers": [
{
"id": "background",
"type": "background",
"layout": {"visibility": "visible"},
"paint": {"background-color": "rgba(255, 255, 255, 1)"}
},
{
"id": "background_water",
"type": "fill",
"source": "v3",
"source-layer": "water",
"layout": {
"visibility": "visible"
},
"paint": {
"fill-color": "rgba(103, 166, 196, 0.2)"
},
"filter": [
"==",
"$type",
"Polygon"
]
},
{
"id": "background_boundary",
"type": "line",
"source": "v3",
"source-layer": "boundary",
"layout": {
"line-cap": "round",
"line-join": "round",
"visibility": "visible"
},
"paint": {
"line-color": "rgba(136, 136, 136, 1)",
"line-width": {
"base": 1,
"stops": [
[
3,
1
],
[
5,
1.2
],
[
12,
3
]
]
},
"line-opacity": 0.2
},
"filter": [
"all",
[
"==",
"admin_level",
2
],
[
"==",
"maritime",
0
]
]
},
{
"id": "swisstopo",
"type": "raster",
"source": "swisstopo",
"layout": {"visibility": "visible"},
"paint": {
"raster-opacity": 1.0,
"raster-resampling": "linear"
}
},
{
"id": "wildlife_areas",
"type": "raster",
"metadata": {
"sotlas-map-option": "wildlife"
},
"source": "wildlife_areas",
"layout": {"visibility": "none"},
"paint": {
"raster-opacity": 0.6,
"raster-resampling": "linear"
}
},
{
"id": "wildlife_reserves",
"type": "raster",
"metadata": {
"sotlas-map-option": "wildlife"
},
"source": "wildlife_reserves",
"layout": {"visibility": "none"},
"paint": {
"raster-opacity": 0.6,
"raster-resampling": "linear"
}
},
{
"id": "summits_az",
"type": "fill",
"metadata": {
"sotlas-map-option": "az"
},
"source": "az",
"source-layer": "az",
"layout": {"visibility": "none"},
"minzoom": 12,
"paint": {
"fill-antialias": false,
"fill-color": "rgba(50, 255, 0, 0.4)",
"fill-opacity": {"stops": [[12, 0], [12.5, 0.5]]}
}
},
{
"id": "summits_az_border",
"type": "line",
"metadata": {
"sotlas-map-option": "az"
},
"source": "az",
"source-layer": "az",
"layout": {"visibility": "none"},
"minzoom": 12,
"paint": {
"line-color": "rgba(50, 150, 0, 1)",
"line-opacity": {"stops": [[12, 0], [12.5, 0.5]]},
"line-width": {"stops": [[12, 1], [16, 2]]},
"line-dasharray": [1,1]
}
},
{
"id": "slope_classes",
"type": "raster",
"metadata": {
"sotlas-map-option": "slope_classes"
},
"source": "slope_classes",
"layout": {"visibility": "none"},
"paint": {
"raster-opacity": 0.3,
"raster-resampling": "nearest"
}
},
{
"id": "hiking_trails_raster",
"type": "raster",
"metadata": {
"sotlas-map-option": "difficulty"
},
"source": "hiking_trails_raster",
"layout": {"visibility": "none"},
"paint": {
"raster-opacity": 0.6,
"raster-resampling": "linear"
}
},
{
"id": "skiing_trails_raster",
"type": "raster",
"metadata": {
"sotlas-map-option": "skiing"
},
"source": "skiing_trails_raster",
"layout": {"visibility": "none"},
"paint": {
"raster-opacity": 0.6,
"raster-resampling": "linear"
}
},
{
"id": "snowshoe_trails_raster",
"type": "raster",
"metadata": {
"sotlas-map-option": "snowshoe"
},
"source": "snowshoe_trails_raster",
"layout": {"visibility": "none"},
"paint": {
"raster-opacity": 0.6,
"raster-resampling": "linear"
}
},
{
"id": "summits_selected",
"type": "circle",
"source": "summits",
"source-layer": "summits",
"filter": ["all", ["in", "code"]],
"layout": {"visibility": "visible"},
"paint": {
"circle-color": "rgba(2, 153, 243, 1)",
"circle-radius": {"stops": [[6, 15], [20, 50]]},
"circle-opacity": 0.75,
"circle-stroke-color": "rgba(210, 255, 0, 0.05)",
"circle-stroke-width": 0,
"circle-stroke-opacity": 1,
"circle-blur": 0.7
}
},
{
"id": "summits_names",
"type": "symbol",
"source": "summits",
"source-layer": "summits",
"minzoom": 10,
"maxzoom": 24,
"filter": ["all", ["in", "code"]],
"layout": {
"visibility": "visible",
"text-field": "{name}\n{code}\n{alt} m",
"text-size": {"stops": [[10, 10], [20, 16]]},
"text-font": ["Frutiger Neue Regular"],
"text-anchor": "bottom",
"text-offset": {"stops": [[10, [0, -1]], [20, [0, -2]]]},
"icon-size": 1,
"symbol-spacing": 250,
"symbol-avoid-edges": false,
"text-keep-upright": true,
"text-transform": "none",
"text-optional": false,
"text-allow-overlap": {"stops": [[18, false], [19, true]]},
"text-ignore-placement": false,
"text-justify": "center",
"text-rotate": 0
},
"paint": {
"text-color": "rgba(255, 255, 255, 1)",
"text-halo-color": "rgba(51, 51, 51, 1)",
"text-halo-width": 1,
"text-halo-blur": 1
}
},
{
"id": "summits_circles_all",
"type": "circle",
"source": "summits",
"source-layer": "summits",
"layout": {"visibility": "none"},
"paint": {
"circle-stroke-color": "rgba(255, 255, 255, 1)",
"circle-color": [
"match",
["get", "points"],
[1],
"rgba(77, 122, 32, 0.5)",
[2],
"rgba(109, 165, 54, 0.5)",
[4],
"rgba(174, 167, 39, 0.5)",
[6],
"rgba(239, 168, 24, 0.5)",
[8],
"rgba(220, 93, 4, 0.5)",
[10],
"rgba(200, 16, 30, 0.5)",
"#000"
],
"circle-stroke-width": {"stops": [[4, 0], [15, 1]]},
"circle-radius": {"stops": [[0, 0.05], [10, 2.5], [22, 12]]}
}
},
{
"id": "summits_circles",
"type": "circle",
"source": "summits",
"source-layer": "summits",
"filter": ["all", ["in", "code"]],
"layout": {"visibility": "visible"},
"paint": {
"circle-stroke-color": "rgba(255, 255, 255, 1)",
"circle-color": [
"match",
["get", "points"],
[1],
"rgba(77, 122, 32, 1)",
[2],
"rgba(109, 165, 54, 1)",
[4],
"rgba(174, 167, 39, 1)",
[6],
"rgba(239, 168, 24, 1)",
[8],
"rgba(220, 93, 4, 1)",
[10],
"rgba(200, 16, 30, 1)",
"#000"
],
"circle-stroke-width": {"stops": [[4, 0], [15, 2]]},
"circle-radius": {"stops": [[0, 0.1], [10, 8], [22, 20]]}
}
},
{
"id": "summits_activations",
"type": "symbol",
"source": "summits",
"source-layer": "summits",
"minzoom": 10,
"maxzoom": 24,
"filter": ["all", ["in", "code"]],
"layout": {
"text-field": "{act}",
"text-font": ["Frutiger Neue Bold"],
"text-size": {"stops": [[10, 8], [20, 16]]},
"text-offset": [0,0.1]
},
"paint": {"text-color": "rgba(255, 255, 255, 1)"}
},
{
"id": "summits_highlight",
"type": "circle",
"source": "summits",
"source-layer": "summits",
"filter": ["all", ["in", "code"]],
"layout": {"visibility": "visible"},
"paint": {
"circle-color": "rgba(2, 243, 198, 1)",
"circle-radius": {"stops": [[6, 15], [20, 50]]},
"circle-opacity": 0.75,
"circle-blur": 0.7
}
},
{
"id": "summits_highlight_alerts",
"type": "circle",
"source": "summits",
"source-layer": "summits",
"filter": ["all", ["in", "code"]],
"layout": {"visibility": "visible"},
"paint": {
"circle-color": "rgba(210, 255, 0, 1)",
"circle-radius": {"stops": [[6, 15], [20, 50]]},
"circle-opacity": 0.55,
"circle-blur": 0.7
}
},
{
"id": "summits_inactive_names",
"type": "symbol",
"metadata": {
"sotlas-map-option": "inactive"
},
"source": "summits_inactive",
"source-layer": "summits_inactive",
"minzoom": 10,
"maxzoom": 24,
"filter": ["all", ["in", "code"]],
"layout": {
"visibility": "none",
"text-field": "{name}\n{code}\n{alt} m\n(inactive)",
"text-size": {"stops": [[10, 10], [20, 16]]},
"text-font": ["Frutiger Neue Regular"],
"text-anchor": "bottom",
"text-offset": {"stops": [[10, [0, -1]], [20, [0, -2]]]},
"icon-size": 1,
"symbol-spacing": 250,
"symbol-avoid-edges": false,
"text-keep-upright": true,
"text-transform": "none",
"text-optional": false,
"text-allow-overlap": {"stops": [[18, false], [19, true]]},
"text-ignore-placement": false,
"text-justify": "center",
"text-rotate": 0
},
"paint": {
"text-color": "rgba(51, 51, 51, 1)",
"text-halo-color": "rgba(255, 255, 255, 1)",
"text-halo-width": 1,
"text-halo-blur": 1,
"text-opacity": 1
}
},
{
"id": "summits_inactive_circles",
"type": "circle",
"metadata": {
"sotlas-map-option": "inactive"
},
"source": "summits_inactive",
"source-layer": "summits_inactive",
"filter": ["all", ["in", "code"]],
"layout": {"visibility": "none"},
"paint": {
"circle-stroke-color": "rgba(255, 255, 255, 1)",
"circle-color": [
"match",
["get", "points"],
[1],
"rgba(77, 122, 32, 0.5)",
[2],
"rgba(109, 165, 54, 0.5)",
[4],
"rgba(174, 167, 39, 0.5)",
[6],
"rgba(239, 168, 24, 0.5)",
[8],
"rgba(220, 93, 4, 0.5)",
[10],
"rgba(200, 16, 30, 0.5)",
"#000"
],
"circle-stroke-width": {"stops": [[4, 0], [15, 2]]},
"circle-radius": {"stops": [[0, 0.1], [10, 8], [22, 20]]}
}
},
{
"id": "regions_areas",
"type": "fill",
"metadata": {
"sotlas-map-option": "regions"
},
"source": "regions",
"source-layer": "areas",
"minzoom": 0,
"layout": {"visibility": "none"},
"paint": {
"fill-opacity": 0.15,
"fill-antialias": false,
"fill-color": "rgba(255, 255, 255, 1)"
}
},
{
"id": "regions_labels",
"type": "symbol",
"metadata": {
"sotlas-map-option": "regions"
},
"source": "regions",
"source-layer": "labels",
"layout": {
"visibility": "none",
"text-field": "{region}",
"text-anchor": "top-left",
"text-justify": "center",
"text-offset": [0.3, 0.3],
"text-font": ["Frutiger Neue Regular"],
"text-size": {"stops": [[6, 8], [10, 16]]}
},
"paint": {
"text-halo-color": "rgba(255, 255, 255, 1)",
"text-halo-width": 0.5,
"text-halo-blur": 1,
"text-translate": [0, 0]
}
}
]
}

Wyświetl plik

@ -1,7 +1,6 @@
{
"version": 8,
"name": "swisstopo_raster",
"metadata": {"maputnik:renderer": "mbgljs", "openmaptiles:version": "3.x"},
"center": [7.969664962869274, 47.021278030856564],
"zoom": 9.333879434342306,
"bearing": 0,
@ -13,7 +12,9 @@
"https://wmts.geo.admin.ch/1.0.0/ch.swisstopo.pixelkarte-farbe/default/current/3857/{z}/{x}/{y}.jpeg"
],
"tileSize": 256,
"maxzoom": 19
"maxzoom": 19,
"bounds": [5.140242, 45.398181, 11.47757, 48.230651],
"attribution": "© swisstopo"
},
"hiking_trails_raster": {
"type": "raster",
@ -21,7 +22,8 @@
"https://wmts.geo.admin.ch/1.0.0/ch.swisstopo.swisstlm3d-wanderwege/default/current/3857/{z}/{x}/{y}.png"
],
"tileSize": 256,
"maxzoom": 18
"maxzoom": 18,
"bounds": [5.140242, 45.398181, 11.47757, 48.230651]
},
"skiing_trails_raster": {
"type": "raster",
@ -29,7 +31,8 @@
"https://wmts.geo.admin.ch/1.0.0/ch.swisstopo-karto.skitouren/default/current/3857/{z}/{x}/{y}.png"
],
"tileSize": 256,
"maxzoom": 17
"maxzoom": 17,
"bounds": [5.140242, 45.398181, 11.47757, 48.230651]
},
"snowshoe_trails_raster": {
"type": "raster",
@ -37,7 +40,8 @@
"https://wmts.geo.admin.ch/1.0.0/ch.swisstopo-karto.schneeschuhrouten/default/current/3857/{z}/{x}/{y}.png"
],
"tileSize": 256,
"maxzoom": 17
"maxzoom": 17,
"bounds": [5.140242, 45.398181, 11.47757, 48.230651]
},
"wildlife_areas": {
"type": "raster",
@ -45,7 +49,8 @@
"https://wmts.geo.admin.ch/1.0.0/ch.bafu.wrz-wildruhezonen_portal/default/current/3857/{z}/{x}/{y}.png"
],
"tileSize": 256,
"maxzoom": 18
"maxzoom": 18,
"bounds": [5.140242, 45.398181, 11.47757, 48.230651]
},
"wildlife_reserves": {
"type": "raster",
@ -53,7 +58,8 @@
"https://wmts.geo.admin.ch/1.0.0/ch.bafu.wrz-jagdbanngebiete_select/default/current/3857/{z}/{x}/{y}.png"
],
"tileSize": 256,
"maxzoom": 18
"maxzoom": 18,
"bounds": [5.140242, 45.398181, 11.47757, 48.230651]
},
"slope_classes": {
"type": "raster",
@ -61,22 +67,32 @@
"https://wmts.geo.admin.ch/1.0.0/ch.swisstopo.hangneigung-ueber_30/default/current/3857/{z}/{x}/{y}.png"
],
"tileSize": 256,
"maxzoom": 14
"maxzoom": 14,
"bounds": [5.140242, 45.398181, 11.47757, 48.230651]
},
"summits": {
"type": "vector",
"url": "https://1.{mapServer}.map.sotl.as/data/summits.json"
"url": "https://api.maptiler.com/tiles/d6ccc3ec-a677-4fcd-a211-2f2da36965cb/tiles.json?key={key}"
},
"summits_inactive": {
"type": "vector",
"url": "https://1.{mapServer}.map.sotl.as/data/summits_inactive.json"
"url": "https://api.maptiler.com/tiles/ac4e1bc3-fbfb-4830-8279-675cc18f86f0/tiles.json?key={key}"
},
"regions": {
"type": "vector",
"url": "https://1.{mapServer}.map.sotl.as/data/regions.json"
"url": "https://api.maptiler.com/tiles/2d324268-fe52-4875-96ca-bc5692fc1225/tiles.json?key={key}"
},
"az": {
"type": "vector",
"url": "https://api.maptiler.com/tiles/e3f0b69a-1a14-4a8c-933a-4c4e134fdaa3/tiles.json?key={key}"
},
"v3": {
"url": "https://api.maptiler.com/tiles/v3/tiles.json?key={key}",
"type": "vector",
"maxzoom": 10
}
},
"sprite": "https://vectortiles.geo.admin.ch/styles/ch.swisstopo.leichte-basiskarte.vt/v1.0.0/sprite/sprite",
"sprite": "https://vectortiles.geo.admin.ch/styles/ch.swisstopo.leichte-basiskarte.vt/sprite/sprite",
"glyphs": "https://vectortiles.geo.admin.ch/fonts/{fontstack}/{range}.pbf",
"transition": {},
"layers": [
@ -86,6 +102,68 @@
"layout": {"visibility": "visible"},
"paint": {"background-color": "rgba(255, 255, 255, 1)"}
},
{
"id": "background_water",
"type": "fill",
"source": "v3",
"source-layer": "water",
"layout": {
"visibility": "visible"
},
"paint": {
"fill-color": "rgba(103, 166, 196, 0.2)"
},
"filter": [
"==",
"$type",
"Polygon"
]
},
{
"id": "background_boundary",
"type": "line",
"source": "v3",
"source-layer": "boundary",
"layout": {
"line-cap": "round",
"line-join": "round",
"visibility": "visible"
},
"paint": {
"line-color": "rgba(136, 136, 136, 1)",
"line-width": {
"base": 1,
"stops": [
[
3,
1
],
[
5,
1.2
],
[
12,
3
]
]
},
"line-opacity": 0.2
},
"filter": [
"all",
[
"==",
"admin_level",
2
],
[
"==",
"maritime",
0
]
]
},
{
"id": "swisstopo",
"type": "raster",
@ -122,6 +200,39 @@
"raster-resampling": "linear"
}
},
{
"id": "summits_az",
"type": "fill",
"metadata": {
"sotlas-map-option": "az"
},
"source": "az",
"source-layer": "az",
"layout": {"visibility": "none"},
"minzoom": 12,
"paint": {
"fill-antialias": false,
"fill-color": "rgba(50, 255, 0, 0.4)",
"fill-opacity": {"stops": [[12, 0], [12.5, 0.5]]}
}
},
{
"id": "summits_az_border",
"type": "line",
"metadata": {
"sotlas-map-option": "az"
},
"source": "az",
"source-layer": "az",
"layout": {"visibility": "none"},
"minzoom": 12,
"paint": {
"line-color": "rgba(50, 150, 0, 1)",
"line-opacity": {"stops": [[12, 0], [12.5, 0.5]]},
"line-width": {"stops": [[12, 1], [16, 2]]},
"line-dasharray": [1,1]
}
},
{
"id": "slope_classes",
"type": "raster",
@ -220,10 +331,39 @@
"paint": {
"text-color": "rgba(51, 51, 51, 1)",
"text-halo-color": "rgba(255, 255, 255, 1)",
"text-halo-width": 1,
"text-halo-width": 1.5,
"text-halo-blur": 1
}
},
{
"id": "summits_circles_all",
"type": "circle",
"source": "summits",
"source-layer": "summits",
"layout": {"visibility": "none"},
"paint": {
"circle-stroke-color": "rgba(255, 255, 255, 1)",
"circle-color": [
"match",
["get", "points"],
[1],
"rgba(77, 122, 32, 0.5)",
[2],
"rgba(109, 165, 54, 0.5)",
[4],
"rgba(174, 167, 39, 0.5)",
[6],
"rgba(239, 168, 24, 0.5)",
[8],
"rgba(220, 93, 4, 0.5)",
[10],
"rgba(200, 16, 30, 0.5)",
"#000"
],
"circle-stroke-width": {"stops": [[4, 0], [15, 1]]},
"circle-radius": {"stops": [[0, 0.05], [10, 2.5], [22, 12]]}
}
},
{
"id": "summits_circles",
"type": "circle",
@ -281,9 +421,20 @@
"circle-color": "rgba(2, 243, 198, 1)",
"circle-radius": {"stops": [[6, 15], [20, 50]]},
"circle-opacity": 0.75,
"circle-stroke-color": "rgba(210, 255, 0, 0.05)",
"circle-stroke-width": 0,
"circle-stroke-opacity": 1,
"circle-blur": 0.7
}
},
{
"id": "summits_highlight_alerts",
"type": "circle",
"source": "summits",
"source-layer": "summits",
"filter": ["all", ["in", "code"]],
"layout": {"visibility": "visible"},
"paint": {
"circle-color": "rgba(210, 255, 0, 1)",
"circle-radius": {"stops": [[6, 15], [20, 50]]},
"circle-opacity": 0.55,
"circle-blur": 0.7
}
},

Wyświetl plik

@ -0,0 +1,419 @@
{
"version": 8,
"name": "toposvalbard",
"center": [16.765892, 78.112112],
"zoom": 6,
"bearing": 0,
"pitch": 0,
"sources": {
"toposvalbard": {
"type": "raster",
"tiles": [
"https://geodata.npolar.no/arcgis/rest/services/Basisdata/NP_Basiskart_Svalbard_WMTS_3857/MapServer/tile/{z}/{y}/{x}"
],
"tileSize": 256,
"maxzoom": 13,
"bounds": [7.4670, 73.7357, 36.0502, 81.1569],
"attribution": "© Norwegian Polar Institute"
},
"summits": {
"type": "vector",
"url": "https://api.maptiler.com/tiles/d6ccc3ec-a677-4fcd-a211-2f2da36965cb/tiles.json?key={key}"
},
"summits_inactive": {
"type": "vector",
"url": "https://api.maptiler.com/tiles/ac4e1bc3-fbfb-4830-8279-675cc18f86f0/tiles.json?key={key}"
},
"regions": {
"type": "vector",
"url": "https://api.maptiler.com/tiles/2d324268-fe52-4875-96ca-bc5692fc1225/tiles.json?key={key}"
},
"az": {
"type": "vector",
"url": "https://api.maptiler.com/tiles/e3f0b69a-1a14-4a8c-933a-4c4e134fdaa3/tiles.json?key={key}"
},
"v3": {
"url": "https://api.maptiler.com/tiles/v3/tiles.json?key={key}",
"type": "vector",
"maxzoom": 10
}
},
"sprite": "https://sotl.as/sprites",
"glyphs": "https://api.maptiler.com/fonts/{fontstack}/{range}.pbf?key={key}",
"transition": {},
"layers": [
{
"id": "background",
"type": "background",
"layout": {"visibility": "visible"},
"paint": {"background-color": "rgba(255, 255, 255, 1)"}
},
{
"id": "background_water",
"type": "fill",
"source": "v3",
"source-layer": "water",
"layout": {
"visibility": "visible"
},
"paint": {
"fill-color": "rgba(103, 166, 196, 0.2)"
},
"filter": [
"==",
"$type",
"Polygon"
]
},
{
"id": "background_boundary",
"type": "line",
"source": "v3",
"source-layer": "boundary",
"layout": {
"line-cap": "round",
"line-join": "round",
"visibility": "visible"
},
"paint": {
"line-color": "rgba(136, 136, 136, 1)",
"line-width": {
"base": 1,
"stops": [
[
3,
1
],
[
5,
1.2
],
[
12,
3
]
]
},
"line-opacity": 0.2
},
"filter": [
"all",
[
"==",
"admin_level",
2
],
[
"==",
"maritime",
0
]
]
},
{
"id": "toposvalbard",
"type": "raster",
"source": "toposvalbard",
"layout": {"visibility": "visible"},
"paint": {
"raster-opacity": 0.75,
"raster-resampling": "linear"
}
},
{
"id": "summits_az",
"type": "fill",
"metadata": {
"sotlas-map-option": "az"
},
"source": "az",
"source-layer": "az",
"layout": {"visibility": "none"},
"minzoom": 12,
"paint": {
"fill-antialias": false,
"fill-color": "rgba(255, 255, 0, 1)",
"fill-opacity": {"stops": [[12, 0], [12.5, 0.5]]}
}
},
{
"id": "summits_az_border",
"type": "line",
"metadata": {
"sotlas-map-option": "az"
},
"source": "az",
"source-layer": "az",
"layout": {"visibility": "none"},
"minzoom": 12,
"paint": {
"line-color": "rgba(235, 196, 0, 1)",
"line-opacity": {"stops": [[12, 0], [12.5, 0.5]]},
"line-width": {"stops": [[12, 1], [16, 3]]}
}
},
{
"id": "summits_selected",
"type": "circle",
"source": "summits",
"source-layer": "summits",
"filter": ["all", ["in", "code"]],
"layout": {"visibility": "visible"},
"paint": {
"circle-color": "rgba(2, 153, 243, 1)",
"circle-radius": {"stops": [[6, 15], [20, 50]]},
"circle-opacity": 0.75,
"circle-stroke-color": "rgba(210, 255, 0, 0.05)",
"circle-stroke-width": 0,
"circle-stroke-opacity": 1,
"circle-blur": 0.7
}
},
{
"id": "summits_names",
"type": "symbol",
"source": "summits",
"source-layer": "summits",
"minzoom": 10,
"maxzoom": 24,
"filter": ["all", ["in", "code"]],
"layout": {
"visibility": "visible",
"text-field": "{name}\n{code}\n{alt} m",
"text-size": {"stops": [[10, 10], [20, 16]]},
"text-font": ["Noto Sans Regular"],
"text-anchor": "bottom",
"text-offset": {"stops": [[10, [0, -1]], [20, [0, -2]]]},
"icon-size": 1,
"symbol-spacing": 250,
"symbol-avoid-edges": false,
"text-keep-upright": true,
"text-transform": "none",
"text-optional": false,
"text-allow-overlap": {"stops": [[18, false], [19, true]]},
"text-ignore-placement": false,
"text-justify": "center",
"text-rotate": 0
},
"paint": {
"text-color": "rgba(51, 51, 51, 1)",
"text-halo-color": "rgba(255, 255, 255, 1)",
"text-halo-width": 1,
"text-halo-blur": 1
}
},
{
"id": "summits_circles_all",
"type": "circle",
"source": "summits",
"source-layer": "summits",
"layout": {"visibility": "none"},
"paint": {
"circle-stroke-color": "rgba(255, 255, 255, 1)",
"circle-color": [
"match",
["get", "points"],
[1],
"rgba(77, 122, 32, 0.5)",
[2],
"rgba(109, 165, 54, 0.5)",
[4],
"rgba(174, 167, 39, 0.5)",
[6],
"rgba(239, 168, 24, 0.5)",
[8],
"rgba(220, 93, 4, 0.5)",
[10],
"rgba(200, 16, 30, 0.5)",
"#000"
],
"circle-stroke-width": {"stops": [[4, 0], [15, 1]]},
"circle-radius": {"stops": [[0, 0.05], [10, 2.5], [22, 12]]}
}
},
{
"id": "summits_circles",
"type": "circle",
"source": "summits",
"source-layer": "summits",
"filter": ["all", ["in", "code"]],
"layout": {"visibility": "visible"},
"paint": {
"circle-stroke-color": "rgba(255, 255, 255, 1)",
"circle-color": [
"match",
["get", "points"],
[1],
"rgba(77, 122, 32, 1)",
[2],
"rgba(109, 165, 54, 1)",
[4],
"rgba(174, 167, 39, 1)",
[6],
"rgba(239, 168, 24, 1)",
[8],
"rgba(220, 93, 4, 1)",
[10],
"rgba(200, 16, 30, 1)",
"#000"
],
"circle-stroke-width": {"stops": [[4, 0], [15, 2]]},
"circle-radius": {"stops": [[0, 0.1], [10, 8], [22, 20]]}
}
},
{
"id": "summits_activations",
"type": "symbol",
"source": "summits",
"source-layer": "summits",
"minzoom": 10,
"maxzoom": 24,
"filter": ["all", ["in", "code"]],
"layout": {
"text-field": "{act}",
"text-font": ["Noto Sans Bold"],
"text-size": {"stops": [[10, 8], [20, 16]]},
"text-offset": [0,0.1]
},
"paint": {"text-color": "rgba(255, 255, 255, 1)"}
},
{
"id": "summits_highlight",
"type": "circle",
"source": "summits",
"source-layer": "summits",
"filter": ["all", ["in", "code"]],
"layout": {"visibility": "visible"},
"paint": {
"circle-color": "rgba(2, 243, 198, 1)",
"circle-radius": {"stops": [[6, 15], [20, 50]]},
"circle-opacity": 0.75,
"circle-blur": 0.7
}
},
{
"id": "summits_highlight_alerts",
"type": "circle",
"source": "summits",
"source-layer": "summits",
"filter": ["all", ["in", "code"]],
"layout": {"visibility": "visible"},
"paint": {
"circle-color": "rgba(210, 255, 0, 1)",
"circle-radius": {"stops": [[6, 15], [20, 50]]},
"circle-opacity": 0.55,
"circle-blur": 0.7
}
},
{
"id": "summits_inactive_names",
"type": "symbol",
"metadata": {
"sotlas-map-option": "inactive"
},
"source": "summits_inactive",
"source-layer": "summits_inactive",
"minzoom": 10,
"maxzoom": 24,
"filter": ["all", ["in", "code"]],
"layout": {
"visibility": "none",
"text-field": "{name}\n{code}\n{alt} m\n(inactive)",
"text-size": {"stops": [[10, 10], [20, 16]]},
"text-font": ["Noto Sans Regular"],
"text-anchor": "bottom",
"text-offset": {"stops": [[10, [0, -1]], [20, [0, -2]]]},
"icon-size": 1,
"symbol-spacing": 250,
"symbol-avoid-edges": false,
"text-keep-upright": true,
"text-transform": "none",
"text-optional": false,
"text-allow-overlap": {"stops": [[18, false], [19, true]]},
"text-ignore-placement": false,
"text-justify": "center",
"text-rotate": 0
},
"paint": {
"text-color": "rgba(51, 51, 51, 1)",
"text-halo-color": "rgba(255, 255, 255, 1)",
"text-halo-width": 1,
"text-halo-blur": 1,
"text-opacity": 1
}
},
{
"id": "summits_inactive_circles",
"type": "circle",
"metadata": {
"sotlas-map-option": "inactive"
},
"source": "summits_inactive",
"source-layer": "summits_inactive",
"filter": ["all", ["in", "code"]],
"layout": {"visibility": "none"},
"paint": {
"circle-stroke-color": "rgba(255, 255, 255, 1)",
"circle-color": [
"match",
["get", "points"],
[1],
"rgba(77, 122, 32, 0.5)",
[2],
"rgba(109, 165, 54, 0.5)",
[4],
"rgba(174, 167, 39, 0.5)",
[6],
"rgba(239, 168, 24, 0.5)",
[8],
"rgba(220, 93, 4, 0.5)",
[10],
"rgba(200, 16, 30, 0.5)",
"#000"
],
"circle-stroke-width": {"stops": [[4, 0], [15, 2]]},
"circle-radius": {"stops": [[0, 0.1], [10, 8], [22, 20]]}
}
},
{
"id": "regions_areas",
"type": "fill",
"metadata": {
"sotlas-map-option": "regions"
},
"source": "regions",
"source-layer": "areas",
"minzoom": 0,
"layout": {"visibility": "none"},
"paint": {
"fill-opacity": 0.1,
"fill-antialias": false,
"fill-color": "rgba(0, 0, 0, 1)"
}
},
{
"id": "regions_labels",
"type": "symbol",
"metadata": {
"sotlas-map-option": "regions"
},
"source": "regions",
"source-layer": "labels",
"layout": {
"visibility": "none",
"text-field": "{region}",
"text-anchor": "top-left",
"text-justify": "center",
"text-offset": [0.3, 0.3],
"text-font": ["Noto Sans Regular"],
"text-size": {"stops": [[6, 8], [10, 16]]}
},
"paint": {
"text-halo-color": "rgba(255, 255, 255, 1)",
"text-halo-width": 0.5,
"text-halo-blur": 1,
"text-translate": [0, 0]
}
}
]
}

Wyświetl plik

@ -30,12 +30,12 @@
{{ props.row.activatorCallsign }}
</template>
</b-table-column>
<b-table-column v-if="showSummitInfo" field="summit.code" label="Summit code" class="nowrap" sortable>
<b-table-column v-if="showSummitInfo" field="summit.code" label="Summit Ref." class="nowrap" sortable>
<CountryFlag v-if="props.row.summit.isoCode && $mq.fullhd" :country="props.row.summit.isoCode" class="flag" />
<router-link v-if="props.row.summit.name" :to="makeSummitLink(props.row.summit.code)">{{ props.row.summit.code }}</router-link>
<span v-else>{{ props.row.summit.code }}</span>
</b-table-column>
<b-table-column v-if="showSummitInfo" field="summit.name" label="Summit name" sortable>
<b-table-column v-if="showSummitInfo" field="summit.name" label="Summit Name" sortable>
<router-link :to="makeSummitLink(props.row.summit.code)">{{ props.row.summit.name }}</router-link>
</b-table-column>
<b-table-column v-if="showSummitInfo" field="summit.altitude" label="Altitude" sortable numeric>
@ -180,6 +180,15 @@ export default {
.then(response => {
this.$store.dispatch('reloadAlerts')
})
.catch(err => {
this.$buefy.dialog.alert({
title: 'Error',
message: 'Could not delete alert: ' + err.message,
type: 'is-danger',
ariaRole: 'alertdialog',
ariaModal: true
})
})
}
})
}

Wyświetl plik

@ -17,7 +17,23 @@ export default {
type: Boolean,
default: false
},
stacked: Boolean
height: {
type: [String, Number],
default: 250
},
spaceRatio: {
type: Number,
default: 0.3
},
yMarkers: {
type: Array
},
stacked: Boolean,
colors: Array,
yAxisMode: {
type: String,
default: 'span'
}
},
methods: {
updateChart () {
@ -47,17 +63,20 @@ export default {
this.chart = new Chart(this.$refs.chart, {
data: {
labels,
datasets: datasets
datasets: datasets,
yMarkers: this.yMarkers
},
type: 'bar',
height: 250,
height: parseInt(this.height),
colors: this.colors,
barOptions: {
spaceRatio: 0.3,
spaceRatio: this.spaceRatio,
stacked: this.stacked
},
axisOptions: {
xAxisMode: 'tick',
xIsSeries: this.xIsSeries
xIsSeries: this.xIsSeries,
yAxisMode: this.yAxisMode
}
})
}

Wyświetl plik

@ -0,0 +1,80 @@
<template>
<b-modal :active.sync="active" :on-cancel="cancelInfo" :can-cancel="false">
<div class="box content">
<div class="has-text-centered">
<span class="fp at flag"></span>
</div>
<h3>basemap.at-Karte jetzt verfügbar</h3>
<p>Auf SOTLAS kann man auch die detailliertere basemap.at-Karte nutzen, inkl. Aktivierungszonen. Einfach den Kartentyp umstellen, fertig!</p>
<div class="has-text-centered is-hidden-touch">
<img class="basemapat-info" src="../assets/basemapat-info.png" />
</div>
<div class="action-buttons">
<div class="has-text-centered">
<b-button type="is-info" size="is-medium" @click="switchMap">Jetzt umstellen</b-button>
</div>
<div class="has-text-centered">
<b-button size="is-medium" @click="cancelInfo">OK, cool!</b-button>
</div>
</div>
</div>
</b-modal>
</template>
<script>
import axios from 'axios'
export default {
name: 'BasemapAtInfo',
mounted () {
if (!localStorage.getItem('basemapAtInfoShown')) {
// Check if we are in Austria
axios.get(process.env.VUE_APP_API_URL + '/my_country')
.then(response => {
if (response.data.country === 'AT') {
this.active = true
}
})
}
},
methods: {
cancelInfo () {
this.active = false
localStorage.setItem('basemapAtInfoShown', true)
},
switchMap () {
this.cancelInfo()
this.$store.commit('setMapType', 'basemapat')
}
},
data () {
return {
active: false
}
}
}
</script>
<style scoped>
>>> .modal-content {
max-width: 40rem !important;
max-height: calc(100vh - 80px);
}
.button {
margin: 0.4rem 0.5rem 0.4rem 0.5rem;
width: 100%;
max-width: 20rem;
text-align: center;
}
.action-buttons {
margin-top: 0.75rem;
}
.flag {
font-size: 3rem;
}
.basemapat-info {
max-width: 20rem;
max-height: 30vh;
margin: 0.5rem 0;
}
</style>

Wyświetl plik

@ -28,17 +28,20 @@ export default {
},
mounted () {
if (this.homeQth === null) {
this.$keycloak.loadUserProfile()
.success(profile => {
if (profile.attributes.Lat && profile.attributes.Lat[0] && profile.attributes.Lon && profile.attributes.Lon[0]) {
this.$store.commit('setHomeQth', {
latitude: parseFloat(profile.attributes.Lat[0]),
longitude: parseFloat(profile.attributes.Lon[0])
this.$keycloak.updateToken(60)
.success(() => {
this.$keycloak.loadUserProfile()
.success(profile => {
if (profile.attributes.Lat && profile.attributes.Lat[0] && profile.attributes.Lon && profile.attributes.Lon[0]) {
this.$store.commit('setHomeQth', {
latitude: parseFloat(profile.attributes.Lat[0]),
longitude: parseFloat(profile.attributes.Lon[0])
})
this.calculate()
} else {
this.$store.commit('setHomeQth', undefined)
}
})
this.calculate()
} else {
this.$store.commit('setHomeQth', undefined)
}
})
} else {
this.calculate()

Wyświetl plik

@ -8,7 +8,7 @@
<router-link :to="makeActivatorLink(props.row.otherCallsign.toUpperCase())">{{ props.row.otherCallsign.toUpperCase() }}</router-link>
</b-table-column>
<b-table-column field="band" label="Band" :custom-sort="sortBand" sortable numeric>
{{ bandForFrequency(props.row.band.replace('MHz', '')) }}
{{ bandForDbFrequency(props.row.band) }}
</b-table-column>
<b-table-column field="mode" label="Mode" sortable>
<ModeLabel :mode="props.row.mode" />
@ -31,8 +31,8 @@ export default {
},
methods: {
sortBand (a, b, isAsc) {
let fa = parseFloat(a.band.replace('MHz', ''))
let fb = parseFloat(b.band.replace('MHz', ''))
let fa = this.dbFrequencyToMHz(a.band)
let fb = this.dbFrequencyToMHz(b.band)
if (fa < fb) {
return (isAsc ? -1 : 1)
} else if (fa === fb) {

Wyświetl plik

@ -15,6 +15,14 @@
<p class="control">
<b-button type="is-info" outlined size="is-small" v-clipboard:copy="latitude + ',' + longitude" v-clipboard:success="onCopySuccess" v-clipboard:error="onCopyError">Copy</b-button>
</p>
<p v-if="haveAz" class="control">
<b-dropdown>
<b-button slot="trigger" type="is-info" outlined size="is-small" icon-left="file-download" icon-right="angle-down">AZ</b-button>
<b-dropdown-item custom disabled><b>Activation zone</b></b-dropdown-item>
<b-dropdown-item has-link><a :href="makeAzUrlForType('gpx')">GPX file</a></b-dropdown-item>
<b-dropdown-item has-link><a :href="makeAzUrlForType('geojson')">GeoJSON file</a></b-dropdown-item>
</b-dropdown>
</p>
</b-field>
</div>
<div v-if="showMaidenhead" class="locator">Locator: {{ maidenhead }}</div>
@ -52,6 +60,7 @@ export default {
},
mounted () {
this.loadElevation()
this.checkAz()
},
created () {
proj4.defs('EPSG:29900', '+proj=tmerc +lat_0=53.5 +lon_0=-8 +k=1.000035 +x_0=200000 +y_0=250000 +ellps=mod_airy +towgs84=482.5,-130.6,564.6,-1.042,-0.214,-0.631,8.15 +units=m +no_defs')
@ -83,6 +92,9 @@ export default {
},
longitude () {
this.loadElevation()
},
reference () {
this.checkAz()
}
},
methods: {
@ -103,7 +115,7 @@ export default {
if (!this.latitude || !this.longitude || !this.showElevation) {
return
}
axios.post('https://ele.sotl.as/api', [[this.latitude, this.longitude]])
axios.post(process.env.VUE_APP_ELEVATION_API_URL, [[this.latitude, this.longitude]])
.then(result => {
this.elevation = Math.round(result.data[0])
})
@ -111,11 +123,31 @@ export default {
convertLatLonToGrid (lat, lon, epsg) {
let inp = [lon, lat]
return proj4(epsg, inp)
},
checkAz () {
if (!this.reference) {
return
}
axios.head(this.makeAzUrlForType('gpx'))
.then(response => {
if (response.status === 200) {
this.haveAz = true
} else {
this.haveAz = false
}
})
.catch(e => {
this.haveAz = false
})
},
makeAzUrlForType (type) {
return process.env.VUE_APP_AZ_URL + '/' + this.reference.replace('-', '/') + '.' + type
}
},
data () {
return {
elevation: null,
haveAz: false,
actions: [
{
name: 'Geoportail (FR)',
@ -129,7 +161,8 @@ export default {
name: 'IGN',
url: () => {
if (this.reference && this.reference.match('^(EA[1-9]|ZB2)/')) {
return `http://www.ign.es/iberpix2/visor/?&x=${this.longitude}&y=${this.latitude}&level=15&srid=4258&visible=MTN`
let p = this.convertLatLonToGrid(this.latitude, this.longitude, 'EPSG:3857')
return `https://componentes.cnig.es/api-core/?center=${p[0]},${p[1]}&zoom=16&controls=scale*true&plugins=toc,zoompanel,measurebar,mousesrs&layers=WMTS*https://www.ign.es/wmts/mapa-raster?*MTN*GoogleMapsCompatible*Map*false*image/jpeg*false*false*true&projection=EPSG:3857*m`
}
}
},
@ -188,7 +221,7 @@ export default {
url: () => {
if (this.reference && this.reference.match('^D[LM]/')) {
let p = this.convertLatLonToGrid(this.latitude, this.longitude, 'EPSG:25832')
return `http://sg.geodatenzentrum.de/web_bkg_webmap/applications/bkgmaps/minimal.html?zoom=11&lat=${p[1]}&lon=${p[0]}&layers=B000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFT`
return `https://sg.geodatenzentrum.de/web_bkg_webmap/applications/bkgmaps/minimal.html?zoom=11&lat=${p[1]}&lon=${p[0]}&layers=B000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFT`
}
}
},
@ -244,6 +277,14 @@ export default {
}
}
},
{
name: 'Austrian Map',
url: () => {
if (this.reference && this.reference.match('^OE/')) {
return `https://maps.bev.gv.at/#/center/${this.longitude},${this.latitude}/zoom/13`
}
}
},
{
name: 'Basemap.at',
url: () => {
@ -267,7 +308,7 @@ export default {
url: () => {
if (this.reference && this.reference.match('^TF/')) {
let p = this.convertLatLonToGrid(this.latitude, this.longitude, 'EPSG:3057')
return `http://kortasja.lmi.is/mapview/?application=kortasja&lang=is&center=${p[0]},${p[1]}&zoom=11&layers=219,225,228,286,221 X`
return `https://kortasja.lmi.is/mapview/?application=kortasja&lang=is&center=${p[0]},${p[1]}&zoom=11&layers=219,225,228,286,221 X`
}
}
},
@ -302,7 +343,7 @@ export default {
name: 'LocationSA',
url: () => {
if (this.reference && this.reference.match('^VK5/')) {
return `http://location.sa.gov.au/viewer/?map=topographic&x=${this.longitude}&y=${this.latitude}&z=16&uids=&pinx=${this.longitude}&piny=${this.latitude}&pinTitle=&pinText=%%sumCode%%`
return `https://location.sa.gov.au/viewer/?map=topographic&x=${this.longitude}&y=${this.latitude}&z=16&uids=&pinx=${this.longitude}&piny=${this.latitude}&pinTitle=&pinText=%%sumCode%%`
}
}
},
@ -371,7 +412,7 @@ export default {
{
name: 'Gaia GPS',
url: () => {
return `https://www.gaiagps.com/map/?loc=14/${this.longitude}/${this.latitude}&layer=GaiaTopoRasterMeters`
return `https://www.gaiagps.com/map/?loc=14/${this.longitude}/${this.latitude}`
}
},
{
@ -404,12 +445,26 @@ export default {
return `https://www.opentopomap.org/#marker=16/${this.latitude}/${this.longitude}`
}
},
{
name: 'Activation Zone Estimator',
url: () => {
if (this.reference) {
return `https://activation.zone/?summitRef=${this.reference}`
}
}
},
{
name: 'SummitPost',
url: () => {
return `https://www.summitpost.org/object_list.php?object_type=1&distance_lat_1=${this.latitude}&distance_lon_1=${this.longitude}&map_1=1`
}
},
{
name: 'Peakbagger.com',
url: () => {
return `https://peakbagger.com/search.aspx?tid=R&lat=${this.latitude}&lon=${this.longitude}&ss=`
}
},
{
name: 'SOTA Summits',
url: () => {

Wyświetl plik

@ -7,9 +7,9 @@
<b-dropdown-item has-link><a :href="makeUrlForType('geojson')">GeoJSON file</a></b-dropdown-item>
<b-dropdown-item separator />
<b-dropdown-item custom disabled><b>Label options</b></b-dropdown-item>
<b-dropdown-item custom><b-checkbox v-model="nameopts" native-value="name">Summit name</b-checkbox></b-dropdown-item>
<b-dropdown-item custom><b-checkbox v-model="nameopts" native-value="altitude">Summit altitude</b-checkbox></b-dropdown-item>
<b-dropdown-item custom><b-checkbox v-model="nameopts" native-value="points">Summit points</b-checkbox></b-dropdown-item>
<b-dropdown-item custom><b-checkbox v-model="nameopts" native-value="name">Summit Name</b-checkbox></b-dropdown-item>
<b-dropdown-item custom><b-checkbox v-model="nameopts" native-value="altitude">Summit Altitude</b-checkbox></b-dropdown-item>
<b-dropdown-item custom><b-checkbox v-model="nameopts" native-value="points">Summit Points</b-checkbox></b-dropdown-item>
</b-dropdown>
</div>
</template>

Wyświetl plik

@ -5,7 +5,7 @@
</header>
<section class="modal-card-body">
<b-field label="Callsign" :message="isOwnCallsign ? '' : 'You are posting an alert for someone else\'s callsign'" :type="isOwnCallsign ? '' : 'is-info'">
<b-input type="text" class="callsign" v-model="callsign" pattern="[a-zA-Z0-9/]{3,}" validation-message="Invalid callsign" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" required />
<b-input type="text" class="callsign" v-model="callsign" pattern="[a-zA-Z0-9\/]{3,}" validation-message="Invalid callsign" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" required />
</b-field>
<b-field label="Summit reference" :message="summitDisplay" :type="summitType" :class="summitLabelClass" expanded>
@ -122,7 +122,10 @@ export default {
}
},
isInputValid () {
return /^[a-zA-Z0-9/]{3,}$/.test(this.callsign) && this.summit !== null && this.isSummitValid(this.summit) && this.date && /^\d\d:\d\d$/.test(this.time) && this.freqMode.length > 0 && (this.freqMode.join(', ').length <= 40 || this.freqMode.join(',').length <= 40)
return /^[a-zA-Z0-9/]{3,}$/.test(this.callsign) &&
(this.summitCodeXxx || (this.summit !== null && this.isSummitValid(this.summit))) &&
this.date && /^\d\d:\d\d$/.test(this.time) &&
this.freqMode.length > 0 && (this.freqMode.join(', ').length <= 40 || this.freqMode.join(',').length <= 40)
},
summitLabelClass () {
if (!this.summit || this.isSummitValid(this.summit)) {
@ -149,22 +152,29 @@ export default {
handler () {
if (this.summitCode) {
// Shorthand input
let summitRegex = /^([A-Z0-9]{1,8})[/ ]([A-Z]{2})[- ]?([0-9]{3})$/i
let summitRegex = /^([A-Z0-9]{1,8})[/ ]([A-Z]{2}|\?\?)[- ]?([0-9]{3}|xxx|\?\?\?)$/i
let matches = this.summitCode.match(summitRegex)
if (matches) {
this.summitCode = (matches[1] + '/' + matches[2] + '-' + matches[3]).toUpperCase()
this.summitLoading = true
axios.get('https://api.sotl.as/summits/' + this.summitCode)
.then(response => {
this.summitLoading = false
this.summitInvalid = false
this.summit = response.data
})
.catch(() => {
this.summitLoading = false
this.summitInvalid = true
this.summit = null
})
if (matches[2].toUpperCase() === 'XX' || matches[2] === '??' || matches[3].toUpperCase() === 'XXX' || matches[3] === '???') {
this.summitInvalid = false
this.summitCodeXxx = true
this.summit = null
} else {
this.summitLoading = true
this.summitCodeXxx = false
axios.get(process.env.VUE_APP_API_URL + '/summits/' + this.summitCode)
.then(response => {
this.summitLoading = false
this.summitInvalid = false
this.summit = response.data
})
.catch(() => {
this.summitLoading = false
this.summitInvalid = true
this.summit = null
})
}
} else {
this.summit = null
this.summitInvalid = false
@ -248,6 +258,19 @@ export default {
this.$store.dispatch('reloadAlerts')
this.$parent.close()
})
.catch(err => {
let errorText = err.message
if (err.response && err.response.data) {
errorText = err.response.data
}
this.$buefy.dialog.alert({
title: 'Error',
message: 'Could not post alert: ' + errorText,
type: 'is-danger',
ariaRole: 'alertdialog',
ariaModal: true
})
})
.finally(() => {
this.posting = false
})
@ -331,6 +354,7 @@ export default {
comments: '',
summit: null,
summitInvalid: false,
summitCodeXxx: false,
summitLoading: false,
timeZone: 'utc',
posting: false

Wyświetl plik

@ -19,7 +19,7 @@
<b-field label="Frequency" :message="maybeKhz ? 'Do you really mean ' + frequency + ' MHz, or are you missing a dot?' : ''" :type="maybeKhz ? 'is-warning' : ''">
<b-field :type="maybeKhz ? 'is-warning' : ''">
<b-input v-model="frequency" type="number" step="any" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" required />
<FrequencyInput v-model="frequency" />
<p class="control">
<span class="button is-static">MHz</span>
</p>
@ -49,10 +49,11 @@ import utils from '../mixins/utils.js'
import prefs from '../mixins/prefs.js'
import sotawatch from '../mixins/sotawatch.js'
import NearbySummitsList from './NearbySummitsList.vue'
import FrequencyInput from './FrequencyInput.vue'
export default {
components: {
NearbySummitsList
NearbySummitsList, FrequencyInput
},
mixins: [utils, prefs, sotawatch],
props: {
@ -140,7 +141,7 @@ export default {
if (matches) {
this.summitCode = (matches[1] + '/' + matches[2] + '-' + matches[3]).toUpperCase()
this.summitLoading = true
axios.get('https://api.sotl.as/summits/' + this.summitCode)
axios.get(process.env.VUE_APP_API_URL + '/summits/' + this.summitCode)
.then(response => {
this.summitLoading = false
this.summitInvalid = false
@ -217,6 +218,19 @@ export default {
this.$parent.close()
})
.catch(err => {
let errorText = err.message
if (err.response && err.response.data) {
errorText = err.response.data
}
this.$buefy.dialog.alert({
title: 'Error',
message: 'Could not post spot: ' + errorText,
type: 'is-danger',
ariaRole: 'alertdialog',
ariaModal: true
})
})
.finally(() => {
this.posting = false
})

Wyświetl plik

@ -0,0 +1,47 @@
<template>
<span v-if="databaseCallsign">
{{ callsign }} (<strong><router-link :to="makeActivatorLinkUserId(userId)">{{ databaseCallsign }}</router-link></strong>)
</span>
<span v-else>
<router-link :to="makeActivatorLinkUserId(userId)"><strong>{{ callsign }}</strong></router-link>
</span>
</template>
<script>
import api from '../mixins/api.js'
import utils from '../mixins/utils.js'
export default {
name: 'FirstActivator',
props: {
callsign: String,
userId: Number
},
mixins: [utils, api],
methods: {
loadDatabaseCallsign () {
this.loadActivator(this.userId)
.then(activator => {
if (this.homeCallsign(this.callsign) !== this.homeCallsign(activator.callsign)) {
this.databaseCallsign = this.homeCallsign(activator.callsign)
} else {
this.databaseCallsign = null
}
})
}
},
mounted () {
this.loadDatabaseCallsign()
},
watch: {
userId () {
this.loadDatabaseCallsign()
}
},
data () {
return {
databaseCallsign: null
}
}
}
</script>

Wyświetl plik

@ -16,7 +16,7 @@ export default {
name: 'Footer',
computed: {
version () {
return VERSION + '-' + COMMITHASH.substring(0, 7)
return 'Version ' + COMMITHASH.substring(0, 7)
}
}
}

Wyświetl plik

@ -0,0 +1,16 @@
<template>
<b-input :value="value" type="number" inputmode="decimal" lang="en_EN" step="any" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" required @input="updateValue" />
</template>
<script>
export default {
props: {
value: String
},
methods: {
updateValue (value) {
this.$emit('input', value)
}
}
}
</script>

Wyświetl plik

@ -28,6 +28,18 @@ export default {
suffixY: {
type: String,
default: ''
},
height: {
type: [String, Number],
default: 250
},
spline: {
type: [String, Number],
default: 0
},
regionFill: {
type: Boolean,
default: true
}
},
methods: {
@ -61,7 +73,7 @@ export default {
datasets: datasets
},
type: 'line',
height: 250,
height: parseInt(this.height),
colors: ['red'],
axisOptions: {
xAxisMode: 'tick',
@ -69,7 +81,8 @@ export default {
},
lineOptions: {
hideDots: true,
regionFill: true
regionFill: this.regionFill,
spline: parseInt(this.spline)
},
tooltipOptions: {
formatTooltipX: d => d + this.suffixX,

Wyświetl plik

@ -1,6 +1,6 @@
<template>
<div v-if="!$mq.mobile" class="mapboxgl-ctrl-group mapboxgl-ctrl">
<button :class="{ 'mapboxgl-ctrl-icon': true, 'mapbox-gl-download': true }" type="button" title="Download map" @click="downloadMap" />
<div v-if="!$mq.mobile" class="maplibregl-ctrl-group maplibregl-ctrl">
<button :class="{ 'maplibregl-ctrl-icon': true, 'maplibre-gl-download': true }" type="button" title="Download map" @click="downloadMap" />
</div>
</template>
@ -25,7 +25,7 @@ export default {
</script>
<style scoped>
.mapbox-gl-download {
.maplibre-gl-download {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M15.6 11.676v3.613a.52.52 0 01-.52.52H4.89a.52.52 0 01-.52-.52v-3.613H3.33v3.613c0 .86.7 1.56 1.56 1.56h10.19c.86 0 1.56-.7 1.56-1.56v-3.613z'/%3E%3Cpath d='M13.216 10.402l-.735-.735-1.975 1.975V3.54h-1.04v8.103L7.49 9.667l-.735.735 3.23 3.23z'/%3E%3C/svg%3E");
}
</style>

Wyświetl plik

@ -15,7 +15,7 @@
import MapboxDraw from '@mapbox/mapbox-gl-draw'
import haversineDistance from 'haversine-distance'
import cheapRuler from 'cheap-ruler'
import togpx from 'togpx'
import GeoJsonToGpx from '@dwayneparton/geojson-to-gpx'
import moment from 'moment'
import axios from 'axios'
import utils from '../mixins/utils.js'
@ -295,8 +295,9 @@ export default {
this.addElevations(all)
.then(() => {
loadingComponent.close()
let gpx = togpx(all)
let blob = new Blob([gpx], { type: 'application/gpx+xml' })
let gpx = GeoJsonToGpx(all)
let gpxString = new XMLSerializer().serializeToString(gpx)
let blob = new Blob([gpxString], { type: 'application/gpx+xml' })
let url = window.URL.createObjectURL(blob)
let link = document.createElement('a')
link.download = 'sotlas-' + moment().format('YYYYMMDD-HHmmss') + '.gpx'
@ -396,7 +397,7 @@ export default {
}
this.loading = true
axios.post('https://ele.sotl.as/api', eleCoordinates)
axios.post(process.env.VUE_APP_ELEVATION_API_URL, eleCoordinates)
.then(result => {
this.chartData = result.data.map((elevation, i) => {
return {
@ -454,7 +455,7 @@ export default {
}
let coordsSwapped = feature.geometry.coordinates.map(coord => [coord[1], coord[0]])
return axios.post('https://ele.sotl.as/api', coordsSwapped)
return axios.post(process.env.VUE_APP_ELEVATION_API_URL, coordsSwapped)
.then(result => {
result.data.forEach((elevation, index) => {
if (feature.geometry.coordinates[index].length === 2) {

Wyświetl plik

@ -1,6 +1,6 @@
<template>
<div class="mapboxgl-ctrl-group mapboxgl-ctrl">
<button :class="{ 'enlarge-control': true, 'mapboxgl-ctrl-fullscreen': !isEnlarged, 'mapboxgl-ctrl-shrink': isEnlarged }" type="button" :title="isEnlarged ? 'Shrink' : 'Enlarge'" @click="$emit('enlarge')"><span class="mapboxgl-ctrl-icon"></span></button>
<div class="maplibregl-ctrl-group maplibregl-ctrl">
<button :class="{ 'enlarge-control': true, 'maplibregl-ctrl-fullscreen': !isEnlarged, 'maplibregl-ctrl-shrink': isEnlarged }" type="button" :title="isEnlarged ? 'Shrink' : 'Enlarge'" @click="$emit('enlarge')"><span class="maplibregl-ctrl-icon"></span></button>
</div>
</template>

Wyświetl plik

@ -1,6 +1,6 @@
<template>
<div :class="{ 'mapboxgl-ctrl-group': true, 'mapboxgl-ctrl': true, 'mapbox-gl-filter-container': true }">
<button :class="{ 'mapboxgl-ctrl-icon': true, 'mapbox-gl-filter': true, active: active }" type="button" title="Toggle filter" @click="toggleFilter" />
<div :class="{ 'maplibregl-ctrl-group': true, 'maplibregl-ctrl': true, 'maplibre-gl-filter-container': true }">
<button :class="{ 'maplibregl-ctrl-icon': true, 'maplibre-gl-filter': true, active: active }" type="button" title="Toggle filter" @click="toggleFilter" />
<div v-if="open" class="filter-container">
<div class="filter-criterion">
<b-field>
@ -138,7 +138,7 @@ export default {
let filterPromises = []
if (this.activationsEnabled) {
if (this.activationsFrom && this.activationsTo && this.activationsTo < this.activationsFrom) {
if (this.activationsFrom && this.activationsTo && parseInt(this.activationsTo) < parseInt(this.activationsFrom)) {
let tmp = this.activationsFrom
this.activationsFrom = this.activationsTo
this.activationsTo = tmp
@ -152,7 +152,7 @@ export default {
}
if (this.pointsEnabled) {
if (this.pointsFrom && this.pointsTo && this.pointsTo < this.pointsFrom) {
if (this.pointsFrom && this.pointsTo && parseInt(this.pointsTo) < parseInt(this.pointsFrom)) {
let tmp = this.pointsFrom
this.pointsFrom = this.pointsTo
this.pointsTo = tmp
@ -172,7 +172,7 @@ export default {
if (this.altitudeTo) {
this.altitudeTo = parseInt(this.altitudeTo)
}
if (this.altitudeFrom && this.altitudeTo && this.altitudeTo < this.altitudeFrom) {
if (this.altitudeFrom && this.altitudeTo && parseInt(this.altitudeTo) < parseInt(this.altitudeFrom)) {
let tmp = this.altitudeFrom
this.altitudeFrom = this.altitudeTo
this.altitudeTo = tmp
@ -313,10 +313,10 @@ export default {
</script>
<style scoped>
.mapbox-gl-filter {
.maplibre-gl-filter {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M16.93 3.62C16.86 3.47 16.71 3.37 16.54 3.37H3.15c-0.17 0-0.32 0.1-0.39 0.25-0.07 0.15-0.05 0.33 0.06 0.46l5.15 6.24v5.76c0 0.15 0.08 0.29 0.2 0.37 0.07 0.04 0.15 0.06 0.23 0.06 0.07 0 0.13-0.01 0.19-0.04l2.89-1.43c0.15-0.07 0.24-0.22 0.24-0.39l0.01-4.32 5.15-6.24c0.11-0.13 0.13-0.31 0.06-0.46zm-5.97 6.27c-0.06 0.08-0.1 0.17-0.1 0.27l-0.01 4.21-2.03 1.01v-5.21c0-0.1-0.03-0.2-0.1-0.27L4.07 4.23H15.62Z' stroke-width='0.06'/%3E%3C/svg%3E%0A");
}
.mapbox-gl-filter.active {
.maplibre-gl-filter.active {
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' fill-rule='evenodd' clip-rule='evenodd' stroke-linejoin='round' stroke-miterlimit='2'%3E%3Cpath d='M16.93 3.62a.43.43 0 00-.39-.25H3.15c-.17 0-.32.1-.39.25a.43.43 0 00.06.46l5.15 6.24v5.76c0 .15.08.29.2.37.07.04.15.06.23.06.07 0 .13-.01.19-.04l2.89-1.43c.15-.07.24-.22.24-.39l.01-4.32 5.15-6.24a.43.43 0 00.06-.46l-.01-.01z' fill='%2333b5e5' fill-rule='nonzero'/%3E%3C/svg%3E");
}
.filter-criterion {
@ -369,12 +369,12 @@ export default {
margin-left: 0.5em;
margin-top: 0.2em;
}
.mapbox-gl-filter-container .filter-container {
.maplibre-gl-filter-container .filter-container {
display: none;
padding: 0 0.5em 0.5em 0.5em;
display: inline-block;
}
.mapbox-gl-filter-container button {
.maplibre-gl-filter-container button {
display: inline-block;
vertical-align: top;
}

Wyświetl plik

@ -1,13 +1,13 @@
<template>
<div :class="{ 'mapboxgl-ctrl-group': true, 'mapboxgl-ctrl': true, 'mapbox-gl-map-options-container': true }">
<div :class="{ 'maplibregl-ctrl-group': true, 'maplibregl-ctrl': true, 'maplibre-gl-map-options-container': true }">
<b-tooltip class="info-tooltip" type="is-info" position="is-right" :active="!infoTooltipShown" always animated multilined label="Webcams and more available – open map options to see!">
<button :class="{ 'mapboxgl-ctrl-icon': true, 'mapbox-gl-map-options': true }" type="button" title="Map options" @click="openCloseMapOptions" />
<button :class="{ 'maplibregl-ctrl-icon': true, 'maplibre-gl-map-options': true }" type="button" title="Map options" @click="openCloseMapOptions" />
</b-tooltip>
<div v-if="open" class="map-options-container">
<div class="map-option">
<b-field grouped>
<b-select v-model="mapType" size="is-small">
<option v-for="(desc, type) in mapTypes" :key="type" :value="type">{{ desc }}</option>
<option v-for="(attrs, type) in mapTypes" :key="type" :value="type">{{ attrs.name }}</option>
</b-select>
</b-field>
</div>
@ -15,41 +15,46 @@
<b-field grouped>
<b-checkbox v-model="mapOptions.regions" size="is-small" @input="setMapOption('regions', $event)">Regions</b-checkbox>
</b-field>
<b-field v-if="mapType !== 'swisstopo_raster'" grouped>
<b-field v-if="mapTypes[mapType].contours" grouped>
<b-checkbox v-model="mapOptions.contours" size="is-small" @input="setMapOption('contours', $event)">Contour lines</b-checkbox>
</b-field>
<b-field v-if="mapType !== 'swisstopo_raster'" grouped>
<b-field v-if="mapTypes[mapType].hillshading" grouped>
<b-checkbox v-model="mapOptions.hillshading" size="is-small" @input="setMapOption('hillshading', $event)">Hillshading</b-checkbox>
</b-field>
<b-field grouped>
<b-checkbox v-model="mapOptions.az" size="is-small" @input="setMapOption('az', $event)">
Activation zones
<b-icon pack="fas" icon="info-circle" size="is-small" type="is-info" @click.native="showActivationZoneInfo" />
</b-checkbox>
</b-field>
</div>
<div class="map-option">
<template v-if="mapType === 'swisstopo' || mapType === 'swisstopo_raster'">
<b-field grouped>
<b-checkbox v-model="mapOptions.difficulty" size="is-small" @input="setMapOption('difficulty', $event)">Wanderwege</b-checkbox>
</b-field>
<b-field grouped>
<b-checkbox v-model="mapOptions.skiing" size="is-small" @input="setMapOption('skiing', $event)">Skirouten</b-checkbox>
</b-field>
<b-field grouped>
<b-checkbox v-model="mapOptions.snowshoe" size="is-small" @input="setMapOption('snowshoe', $event)">Schneeschuhrouten</b-checkbox>
</b-field>
<b-field grouped>
<b-checkbox v-model="mapOptions.slope_classes" size="is-small" @input="setMapOption('slope_classes', $event)">Hangneigungsklassen über 30°</b-checkbox>
</b-field>
<b-field grouped>
<b-checkbox v-model="mapOptions.wildlife" size="is-small" @input="setMapOption('wildlife', $event)">Wildruhezonen und Schutzgebiete</b-checkbox>
</b-field>
</template>
<template v-else>
<b-field grouped>
<b-checkbox v-model="mapOptions.difficulty" size="is-small" @input="setMapOption('difficulty', $event)">Hiking difficulty</b-checkbox>
</b-field>
</template>
<div class="map-option" v-if="mapTypes[mapType].difficulty">
<b-field grouped>
<b-checkbox v-model="mapOptions.difficulty" size="is-small" @input="setMapOption('difficulty', $event)">
Hiking difficulty
<b-icon pack="fas" icon="info-circle" size="is-small" type="is-info" @click.native="showHikingDifficultyInfo" />
</b-checkbox>
</b-field>
<b-field v-if="mapTypes[mapType].skiing" grouped>
<b-checkbox v-model="mapOptions.skiing" size="is-small" @input="setMapOption('skiing', $event)">Ski routes</b-checkbox>
</b-field>
<b-field v-if="mapTypes[mapType].snowshoe" grouped>
<b-checkbox v-model="mapOptions.snowshoe" size="is-small" @input="setMapOption('snowshoe', $event)">Snowshoe routes</b-checkbox>
</b-field>
<b-field v-if="mapTypes[mapType].slope_classes" grouped>
<b-checkbox v-model="mapOptions.slope_classes" size="is-small" @input="setMapOption('slope_classes', $event)">Slope classes over 30°</b-checkbox>
</b-field>
<b-field v-if="mapTypes[mapType].wildlife" grouped>
<b-checkbox v-model="mapOptions.wildlife" size="is-small" @input="setMapOption('wildlife', $event)">Wildlife reserves and areas</b-checkbox>
</b-field>
</div>
<div class="map-option">
<b-field grouped>
<b-checkbox v-model="mapOptions.spots" size="is-small" @input="setMapOption('spots', $event)">Recent spots</b-checkbox>
</b-field>
<b-field grouped>
<b-checkbox v-model="mapOptions.alerts" size="is-small" @input="setMapOption('alerts', $event)">Alerts</b-checkbox>
</b-field>
<b-field grouped>
<b-checkbox v-model="mapOptions.inactive" size="is-small" @input="setMapOption('inactive', $event)">Inactive summits</b-checkbox>
</b-field>
@ -73,6 +78,7 @@ import mapstyle from '../mixins/mapstyle.js'
import prefs from '../mixins/prefs.js'
const RECENT_SPOT_AGE = 30 * 60 * 1000
const MAX_ALERT_AGE = 3 * 60 * 60 * 1000
export default {
name: 'MapOptionsControl',
@ -103,9 +109,21 @@ export default {
return spot.summit.code
})
},
alerts () {
let now = moment.utc()
return this.$store.state.alerts.filter(alert => {
return (now.diff(alert.dateActivated) < MAX_ALERT_AGE)
}).map(alert => {
return alert.summit.code
})
},
mapType: {
get () {
return this.$store.state.mapType
if (!this.mapTypes[this.$store.state.mapType]) {
return Object.keys(this.mapTypes)[0]
} else {
return this.$store.state.mapType
}
},
set (newMapType) {
this.$store.commit('setMapType', newMapType)
@ -122,9 +140,16 @@ export default {
},
immediate: true
},
alerts: {
handler () {
this.updateAlerts()
},
immediate: true
},
mapOptions: {
handler () {
this.updateRecentSpots()
this.updateAlerts()
},
deep: true
},
@ -148,21 +173,53 @@ export default {
this.map.setFilter('summits_highlight', ['in', 'code'])
}
},
updateAlerts () {
if (this.mapOptions.alerts) {
this.map.setFilter('summits_highlight_alerts', ['in', 'code', ...this.alerts])
} else {
this.map.setFilter('summits_highlight_alerts', ['in', 'code'])
}
},
spotsShown () {
return this.mapOptions.spots
},
alertsShown () {
return this.mapOptions.alerts
},
openCloseMapOptions () {
this.open = !this.open
},
setMapOption (option, value) {
this.$store.commit('setMapOption', { option, value })
},
showActivationZoneInfo (event) {
event.preventDefault()
this.$buefy.dialog.alert({
title: 'Activation zones',
message: '<p style="margin-bottom: 0.5em">Activation zone boundaries are currently available for the following associations/regions:</p><ul><li style="margin-bottom: 0.5em"><strong>HB/HB0</strong><br />Calculated using <a href="https://www.swisstopo.admin.ch/de/geodata/height/alti3d.html" target="_blank">swissALTI3D</a> data from swisstopo (spatial resolution 0.5 m, accuracy ± 0.3 – 3 m (1σ) depending on the region).</li><li style="margin-bottom: 0.5em"><strong>OE</strong><br />Calculated using <a href="https://data.bev.gv.at/geonetwork/srv/ger/catalog.search;jsessionid=1F5F6A9D0278E6871FEDB6B87EE0936B#/metadata/eae5f98d-d605-4783-8292-8b913d163cac" target="_blank">BEV ALS DTM</a> data (spatial resolution 1 m, accuracy generally ± 0.5 m, may vary in high altitude).</li><li style="margin-bottom: 0.5em"><strong>W7W</strong><br />Calculated using data from <a href="https://lidarportal.dnr.wa.gov/" target="_blank">Washington States Department of Natural Resources public LIDAR portal</a>.</li></ul><p style="font-size: 0.8em">The activator is always responsible for ensuring that the operation takes place within the activation zone.</p>',
type: 'is-info',
hasIcon: true,
icon: 'info-circle',
iconPack: 'fas'
})
},
showHikingDifficultyInfo (event) {
event.preventDefault()
this.$buefy.dialog.alert({
title: 'Hiking difficulty',
message: '<p style="margin-bottom: 0.5em">The hiking difficulty grading uses the <a href="https://www.sac-cas.ch/fileadmin/Ausbildung_und_Wissen/Sicher_unterwegs/Sicher_unterwegs_Wandern/2020_Berg_Alpinwanderskala_EN.pdf" target="_blank">SAC scale</a>. Colors shown are as follows:</p><ul><li><span style="color: #cccc00">Yellow</span>: T1</li><li><span style="color: #cc0000">Red</span>: T2…T3</li><li><span style="color: #3333cc">Blue</span>: T4…T6</li></ul>',
type: 'is-info',
hasIcon: true,
icon: 'info-circle',
iconPack: 'fas'
})
}
}
}
</script>
<style scoped>
.mapbox-gl-map-options {
.maplibre-gl-map-options {
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg' stroke-linejoin='round' stroke-miterlimit='2'%3E%3Cpath d='M16.847 2.863c-.049 0-.1.009-.15.029l-4.28 1.582-4.33-1.529a1.602 1.602 0 00-1.008-.003L3.257 4.271a.808.808 0 00-.507.748v8.718a.404.404 0 00.553.374l4.28-1.582 4.33 1.528c.327.109.681.11 1.008.004l3.822-1.33a.807.807 0 00.507-.747V3.266a.403.403 0 00-.403-.403zm-8.458 1.47l3.222 1.138v7.198l-3.222-1.137V4.333zm-4.43 8.247V5.306l3.222-1.121v7.204l-.016.006-3.206 1.185zm12.082-.884l-3.222 1.121V5.613l.016-.006 3.206-1.185v7.274zM16.975 15.625H7.7v-.412a.276.276 0 00-.275-.275h-.55a.275.275 0 00-.275.275v.412H3.025a.276.276 0 00-.275.275v.275c0 .151.124.275.275.275H6.6v.412c0 .152.123.275.275.275h.55a.275.275 0 00.275-.275v-.412h9.275a.276.276 0 00.275-.275V15.9a.276.276 0 00-.275-.275z' /%3E%3C/svg%3E");
}
.map-option {
@ -173,12 +230,12 @@ export default {
background-color: #eee;
font-size: 0.8rem;
}
.mapbox-gl-map-options-container .map-options-container {
.maplibre-gl-map-options-container .map-options-container {
display: none;
padding: 0 0.5em 0.5em 0;
display: inline-block;
}
.mapbox-gl-map-options-container button {
.maplibre-gl-map-options-container button {
display: inline-block;
vertical-align: top;
}

Wyświetl plik

@ -25,7 +25,7 @@
<script>
import axios from 'axios'
import togeojson from '@mapbox/togeojson'
import { gpx } from '@tmcw/togeojson'
import { MglGeojsonLayer, MglMarker } from 'vue-mapbox'
import haversineDistance from 'haversine-distance'
import tracks from '../mixins/tracks.js'
@ -41,6 +41,18 @@ export default {
mixins: [tracks],
computed: {
trackLayer () {
let lineColor = '#1cd60d'
let lineOpacity = 0.75
let lineWidth = 3
if (this.route.highlight === true) {
lineColor = '#4fe005'
lineOpacity = 0.85
lineWidth = 4.5
} else if (this.route.highlight === false) {
lineColor = '#86bc6b'
lineOpacity = 0.25
}
return {
type: 'line',
layout: {
@ -48,9 +60,9 @@ export default {
'line-cap': 'round'
},
paint: {
'line-color': this.route.highlight ? '#ff0000' : '#245acd',
'line-width': 3,
'line-opacity': 0.75
'line-color': lineColor,
'line-width': lineWidth,
'line-opacity': lineOpacity
}
}
},
@ -168,7 +180,7 @@ export default {
let dom = (new DOMParser()).parseFromString(response.data, 'text/xml')
this.geoJsonSource = {
type: 'geojson',
data: togeojson.gpx(dom)
data: gpx(dom)
}
})
},

Wyświetl plik

@ -6,14 +6,14 @@
<font-awesome-icon icon="circle" />
<font-awesome-icon :icon="['fas', 'camera-home']" transform="shrink-7 left-0.5" :style="{ color: 'white' }" />
</font-awesome-layers>
<div v-if="webcam.map.clustersize > 1" class="clustersize">+{{ webcam.map.clustersize - 1 }}</div>
<div v-if="webcam.clusterSize > 1" class="clustersize">+{{ webcam.clusterSize - 1 }}</div>
</div>
<MglPopup :closeButton="false" @added="popupAdded">
<div :class="['thumbwrapper', size]">
<a :href="thumbnailHref" target="_blank"><img class="thumb" :src="thumbnailSrc" /></a>
<div class="caption">{{ title }}</div>
<template v-if="webcam.map.clustersize > 1 && size != 'is-small'">
<div class="clustercaption">{{ webcam.map.clustersize - 1 }} more webcam{{ webcam.map.clustersize > 2 ? 's' : '' }}</div>
<template v-if="webcam.clusterSize > 1 && size != 'is-small'">
<div class="clustercaption">{{ webcam.clusterSize - 1 }} more webcam{{ webcam.clusterSize > 2 ? 's' : '' }}</div>
<div class="clusterinfo">zoom in to view</div>
</template>
<div class="attribution">Webcams provided by <a href="https://www.windy.com/" target="_blank">windy.com</a></div>
@ -43,10 +43,10 @@ export default {
return this.webcam.title
},
thumbnailSrc () {
return this.$store.state.mapOptions.webcamsType === 'current' ? this.webcam.image.current.preview : this.webcam.image.daylight.preview
return this.$store.state.mapOptions.webcamsType === 'current' ? this.webcam.images.current.preview : this.webcam.images.daylight.preview
},
thumbnailHref () {
return this.$mq.mobile ? this.webcam.url.current.mobile : this.webcam.url.current.desktop
return 'https://www.windy.com/webcams/' + this.webcam.webcamId
}
},
methods: {

Wyświetl plik

@ -1,6 +1,6 @@
<template>
<div>
<MapWebcam v-for="webcam in webcams" :key="webcam.id" :webcam="webcam" :size="size" />
<MapWebcam v-for="webcam in webcams" :key="webcam.webcamId" :webcam="webcam" :size="size" />
</div>
</template>
@ -32,12 +32,41 @@ export default {
},
loadWebcams () {
// Convert MapBox zoom level to Google Maps like zoom level
let mapZoom = Math.floor(Math.min(this.map.getZoom() + 2, 22))
let mapBounds = this.map.getBounds().getNorthEast().lat + ',' + this.map.getBounds().getNorthEast().lng + ',' + this.map.getBounds().getSouthWest().lat + ',' + this.map.getBounds().getSouthWest().lng + ',' + mapZoom
let mapZoom = Math.floor(Math.min(this.map.getZoom() + 1, 18))
axios.get('https://api.windy.com/api/webcams/v2/map/' + mapBounds, { params: { key: this.windyApiKey, show: 'webcams:location,image,url,map' } })
// Windy v3 API has a limit on the latitude/longitude span relative to the zoom level.
// Ensure that we are within the limit, lower the zoom level if necessary, otherwise
// we will get a 400 response.
let latSpan = Math.abs(this.map.getBounds().getNorthEast().lat - this.map.getBounds().getSouthWest().lat)
let lngSpan = Math.abs(this.map.getBounds().getNorthEast().lng - this.map.getBounds().getSouthWest().lng)
while (mapZoom > 4) {
let maxAllowedLatSpan = 22.5 / Math.pow(2, mapZoom - 4)
let maxAllowedLngSpan = 45 / Math.pow(2, mapZoom - 4)
if (latSpan < maxAllowedLatSpan && lngSpan < maxAllowedLngSpan) {
break
}
mapZoom--
}
if (mapZoom <= 4) {
// We have reached the limit of what we can request via the API - so don't request anything
this.webcams = []
return
}
axios.get('https://api.windy.com/webcams/api/v3/map/clusters', {
headers: { 'X-WINDY-API-KEY': this.windyApiKey },
params: {
northLat: this.map.getBounds().getNorthEast().lat,
eastLon: this.map.getBounds().getNorthEast().lng,
southLat: this.map.getBounds().getSouthWest().lat,
westLon: this.map.getBounds().getSouthWest().lng,
zoom: mapZoom,
include: 'location,images,urls'
}
})
.then(response => {
this.webcams = response.data.result.webcams.filter(webcam => { return webcam.status === 'active' })
this.webcams = response.data.filter(webcam => { return webcam.status === 'active' })
})
}
},

Wyświetl plik

@ -1,12 +1,12 @@
<template>
<MglMap v-if="(mapCenter || bounds) && mapStyle" :mapStyle="mapStyle" :bounds="bounds" :fitBoundsOptions="fitBoundsOptions" :center="mapCenter" :zoom="12.5" :attributionControl="false" @load="onMapLoaded" @click="onMapClicked" @contextmenu="onMapRightClicked" @idle="onMapIdle">
<MglMap v-if="(mapCenter || bounds) && mapStyle" :apiKey="mapApiKey" :key="mapKey" :mapStyle="mapStyle" :bounds="bounds" :fitBoundsOptions="fitBoundsOptions" :center="mapCenter" :zoom="12.5" :attributionControl="false" @load="onMapLoaded" @click="onMapClicked" @contextmenu="onMapRightClicked" @idle="onMapIdle">
<MglGeolocateControl v-if="!$mq.mobile || isEnlarged" :positionOptions="{ enableHighAccuracy: true }" :fitBoundsOptions="{ maxZoom: 12.5 }" :trackUserLocation="true" position="top-right" />
<MglNavigationControl v-if="!$mq.mobile" position="top-right" :showCompass="false" />
<MglScaleControl v-if="!$mq.mobile || isEnlarged" position="bottom-left" />
<div v-if="canEnlarge" class="mapboxgl-ctrl-top-left">
<div v-if="canEnlarge" class="maplibregl-ctrl-top-left">
<MapEnlargeControl :isEnlarged="isEnlarged" @enlarge="$emit('enlarge')" />
</div>
<MglAttributionControl :compact="true" position="bottom-right" />
<MglAttributionControl :compact="$mq.mobile" position="bottom-right" />
<MapRoute v-for="route in routes" :key="route.id" :route="route" />
<MapPhoto v-for="photo in mapPhotos" :key="photo.filename" :summit="summit" :photo="photo" @photoClicked="photo => $emit('photoClicked', photo)" />
@ -26,6 +26,7 @@ import MapWebcams from './MapWebcams.vue'
import mapstyle from '../mixins/mapstyle.js'
import utils from '../mixins/utils.js'
import longtouch from '../mixins/longtouch.js'
import reportMapSession from '../mapsession.js'
export default {
name: 'MiniMap',
@ -101,6 +102,13 @@ export default {
mapOptions.regions = false
mapOptions.inactive = this.showInactiveSummits
return mapOptions
},
mapKey () {
if (this.summit) {
return this.summit.code
} else {
return undefined
}
}
},
methods: {
@ -164,6 +172,8 @@ export default {
this.map.dragPan.disable()
}
this.highlightCurrentSummit()
reportMapSession()
},
onMapClicked (event) {
if (event.mapboxEvent.originalEvent.hitMarker) {
@ -234,10 +244,10 @@ export default {
</script>
<style scoped>
>>> .mapboxgl-canvas-container.mapboxgl-interactive {
>>> .maplibregl-canvas-container.maplibregl-interactive {
cursor: auto;
}
.map >>> .mapboxgl-popup {
.map >>> .maplibregl-popup {
max-width: 400px !important;
}
.zoom-warning {

Wyświetl plik

@ -1,10 +1,16 @@
<template>
<b-navbar wrapper-class="container" :fixed-top="true" :close-on-click="false" :isActive.sync="burgerActive">
<template #brand>
<b-navbar-item tag="router-link" to="/about"><img src="../assets/sotlas.svg" alt="Logo"></b-navbar-item>
<b-navbar-item tag="router-link" to="/about">
<img v-if="$mq.widescreen" src="../assets/sotlas.svg" alt="Logo">
<img v-else src="../assets/sotlas-icon.svg" alt="Logo">
</b-navbar-item>
<b-navbar-item class="clock" tag="div">
<font-awesome-icon :icon="['far', 'clock']" class="faicon" /> {{ clock }}
</b-navbar-item>
<b-navbar-item tag="router-link" to="/solar_history">
<SolarData />
</b-navbar-item>
</template>
<template #end>
<b-navbar-item tag="div">
@ -30,6 +36,7 @@
import moment from 'moment'
import SearchField from '../components/SearchField.vue'
import LoginButton from '../components/LoginButton.vue'
import SolarData from '../components/SolarData.vue'
import utils from '../mixins/utils.js'
import EventBus from '../event-bus'
@ -37,7 +44,7 @@ export default {
name: 'NavBar',
mixins: [ utils ],
components: {
SearchField, LoginButton
SearchField, LoginButton, SolarData
},
props: {
query: {

Wyświetl plik

@ -28,7 +28,7 @@ export default {
this.loading = true
navigator.geolocation.getCurrentPosition(
position => {
axios.get('https://api.sotl.as/summits/near', { params: { lat: position.coords.latitude, lon: position.coords.longitude, limit: 5, maxDistance: 100000 } })
axios.get(process.env.VUE_APP_API_URL + '/summits/near', { params: { lat: position.coords.latitude, lon: position.coords.longitude, limit: 5, maxDistance: 100000 } })
.then(response => {
if (response.data.length === 0) {
alert('No summits within 100 km.')

Wyświetl plik

@ -22,7 +22,7 @@ export default {
},
prefs: {
key: 'photosUploaderPrefs',
props: ['gpsNotificationShown']
props: ['gpsNotificationShown', 'resolutionWarningShown']
},
mixins: [api, prefs],
computed: {
@ -55,6 +55,18 @@ export default {
})
this.gpsNotificationShown = true
}
if (res.data.length > 0 && res.data[0].width < 1600 && res.data[0].height < 1600 && !this.resolutionWarningShown) {
this.$buefy.dialog.alert({
title: 'Low photo resolution',
message: '<p>Your photo has been uploaded successfully, but its resolution is quite low (< 1600 pixels width or height). Please upload original, full resolution photos whenever possible. SOTLAS will automatically resize them as appropriate.</p><p><small>This alert will not appear again for future uploads of low resolution photos.</small></p>',
type: 'is-info',
hasIcon: true,
icon: 'info-circle',
iconPack: 'far'
})
this.resolutionWarningShown = true
}
})
.catch(err => {
error(err)
@ -81,7 +93,8 @@ export default {
},
data () {
return {
gpsNotificationShown: false
gpsNotificationShown: false,
resolutionWarningShown: false
}
}
}

Wyświetl plik

@ -4,7 +4,7 @@
<draggable v-model="myItems" handle=".handle" @change="dragChange">
<figure v-for="(item, index) in myItems" :key="item.src">
<a :href="item.src" :title="item.thumbTitle" @click.prevent="open(index)" @mouseover="$emit('mouseoverPicture', item, index)" @mouseleave="$emit('mouseleavePicture', item, index)">
<img :src="item.msrc" />
<img :src="item.msrc" :width="thumbSize(item).w" :height="thumbSize(item).h" />
</a>
<div class="move-button" v-if="item.editable">
<b-button class="control handle" size="is-small" icon-left="arrows-alt" title="Drag to reorder"></b-button>
@ -78,6 +78,14 @@ export default {
type: Object
}
},
computed: {
thumbMaxW () {
return this.$mq.mobile ? 242 : 300
},
thumbMaxH () {
return this.$mq.mobile ? 104 : 128
}
},
methods: {
open (index, disableAnimation = false) {
let that = this
@ -113,6 +121,19 @@ export default {
if (event.moved) {
this.$emit('movePicture', event.moved.newIndex, event.moved.oldIndex, event.element)
}
},
thumbSize (item) {
let thumbW = item.w
let thumbH = item.h
if (thumbW > this.thumbMaxW) {
thumbH = (thumbH * this.thumbMaxW) / thumbW
thumbW = this.thumbMaxW
}
if (thumbH > this.thumbMaxH) {
thumbW = (thumbW * this.thumbMaxH) / thumbH
thumbH = this.thumbMaxH
}
return { w: Math.round(thumbW), h: Math.round(thumbH) }
}
},
data () {

Wyświetl plik

@ -5,11 +5,11 @@
{{ props.row.TimeOfDay }}
</b-table-column>
<b-table-column field="OtherCallsign" label="Callsign" class="nowrap" sortable>
<CountryFlag :country="isoCodeForCallsign(props.row.OtherCallsign)" class="flag" />
<router-link :to="makeActivatorLink(props.row.OtherCallsign)">{{ props.row.OtherCallsign }}</router-link>
<CountryFlag :country="isoCodeForCallsign(props.row.OtherCallsign.trim())" class="flag" />
<router-link :to="makeActivatorLink(props.row.OtherCallsign.trim())">{{ props.row.OtherCallsign.trim() }}</router-link>
</b-table-column>
<b-table-column field="Band" label="Band" :custom-sort="sortBand" class="nowrap" sortable numeric>
{{ bandForFrequency(props.row.Band.replace('MHz', '')) }}
{{ bandForDbFrequency(props.row.Band) }}
</b-table-column>
<b-table-column field="Mode" label="Mode" class="mode nowrap" sortable>
<ModeLabel :mode="props.row.Mode" />
@ -40,8 +40,8 @@ export default {
mixins: [utils],
methods: {
sortBand (a, b, isAsc) {
let fa = parseFloat(a.Band.replace('MHz', ''))
let fb = parseFloat(b.Band.replace('MHz', ''))
let fa = this.dbFrequencyToMHz(a.Band)
let fb = this.dbFrequencyToMHz(b.Band)
if (fa < fb) {
return (isAsc ? -1 : 1)
} else if (fa === fb) {

Wyświetl plik

@ -86,7 +86,7 @@ export default {
}
@media screen and (min-width: 1024px) and (max-width: 1215px) {
.search-input {
max-width: 11rem;
max-width: 14rem;
}
}
</style>

Wyświetl plik

@ -0,0 +1,88 @@
<template>
<div class="solar-container" v-if="latest !== null">
<div><label>SFI</label>{{ latest.sfi }}</div>
<div><label>SN</label>{{ latest.r }}</div>
<div :class="[kAttribute]"><label>K</label>{{ latest.k }}</div>
<div><label>A</label>{{ latest.a }}</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'SolarData',
mounted () {
this.loadSolarData()
},
computed: {
kAttribute () {
if (this.latest === null) {
return ''
}
if (this.latest.k <= 2) {
return 'k-quiet'
} else if (this.latest.k === 3) {
return 'k-unsettled'
} else if (this.latest.k === 4) {
return 'k-active'
} else if (this.latest.k <= 7) {
return 'k-storm'
} else {
return 'k-severestorm'
}
}
},
methods: {
loadSolarData () {
axios.get(process.env.VUE_APP_API_URL + '/solardata/latest')
.then(response => {
this.latest = response.data
})
}
},
data () {
return {
latest: null
}
}
}
</script>
<style scoped>
.solar-container {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-template-rows: repeat(2, 1fr);
grid-column-gap: 0.3rem;
font-size: 0.8rem;
line-height: 1.05rem;
background-color: #eee;
border-radius: 10px;
padding: 0.15rem 0.4rem;
font-weight: bold;
text-align: right;
}
.solar-container label {
font-size: 0.7rem;
margin-right: 0.2rem;
font-weight: normal;
opacity: 0.6;
}
.solar-container .k-quiet {
color: #106f06;
}
.solar-container .k-unsettled {
color: #817f03;
}
.solar-container .k-active {
color: #8c5903;
}
.solar-container .k-storm {
color: #8d0002;
}
.solar-container .k-severestorm {
color: #7e0053;
}
</style>

Wyświetl plik

@ -32,12 +32,12 @@
<b-table-column field="mode" label="Mode" sortable>
<ModeLabel :mode="props.row.mode" />
</b-table-column>
<b-table-column v-if="showSummitInfo" field="summit.code" label="Summit code" class="nowrap" sortable>
<b-table-column v-if="showSummitInfo" field="summit.code" label="Summit Ref." class="nowrap" sortable>
<CountryFlag v-if="props.row.summit.isoCode && $mq.fullhd" :country="props.row.summit.isoCode" class="flag" />
<router-link v-if="props.row.summit.name" :to="makeSummitLink(props.row.summit.code)">{{ props.row.summit.code }}</router-link>
<span v-else>{{ props.row.summit.code }}</span>
</b-table-column>
<b-table-column v-if="showSummitInfo" field="summit.name" label="Summit name" sortable>
<b-table-column v-if="showSummitInfo" field="summit.name" label="Summit Name" sortable>
<router-link :to="makeSummitLink(props.row.summit.code)">{{ props.row.summit.name }}</router-link>
</b-table-column>
<b-table-column v-if="showSummitInfo" field="summit.altitude" label="Altitude" sortable numeric>
@ -49,7 +49,7 @@
<b-table-column v-if="showSummitInfo" field="summit.activationCount" label="Act." sortable numeric>
<ActivationCount :activationCount="props.row.summit.activationCount" />
</b-table-column>
<b-table-column field="callsign" label="Posted by" sortable>
<b-table-column field="callsign" label="Posted By" sortable>
{{ props.row.callsign }}
</b-table-column>
<b-table-column field="comments" class="comments" label="Comments">
@ -192,6 +192,15 @@ export default {
.then(response => {
this.$store.commit('deleteSpot', spot)
})
.catch(err => {
this.$buefy.dialog.alert({
title: 'Error',
message: 'Could not delete spot: ' + err.message,
type: 'is-danger',
ariaRole: 'alertdialog',
ariaModal: true
})
})
}
})
}

Wyświetl plik

@ -1,7 +1,7 @@
<template>
<b-table :class="{ 'auto-width': autoWidth, summits: true }" default-sort="code" :narrowed="true" :striped="true" :data="data" :mobile-cards="false" :row-class="(row, index) => !row.isValid && 'is-invalid'">
<template slot-scope="props">
<b-table-column field="code" label="Code" class="nowrap" sortable>
<b-table-column field="code" label="Reference" class="nowrap" sortable>
<router-link :to="makeSummitLink(props.row.code)">{{ props.row.code }}</router-link>
</b-table-column>
<b-table-column field="name" label="Name" class="summit-name" sortable>

Wyświetl plik

@ -50,7 +50,7 @@ export default {
let summitPhotos = this.summit.photos
if (this.minDate) {
summitPhotos = summitPhotos.filter(photo => {
return moment(photo.uploadDate).isSameOrAfter(moment(this.minDate))
return photo.uploadDate && moment(photo.uploadDate).isSameOrAfter(moment(this.minDate))
})
}
summitPhotos.forEach(photo => {

Wyświetl plik

@ -13,12 +13,13 @@ import PictureSwipe from './PictureSwipe.vue'
import utils from '../mixins/utils.js'
import photos from '../mixins/photos.js'
import moment from 'moment'
import togpx from 'togpx'
import GeoJsonToGpx from '@dwayneparton/geojson-to-gpx'
export default {
name: 'SummitPhotosGroup',
props: {
photos: Array,
title: String,
summit: Object,
editable: Boolean,
showSummitName: Boolean,
@ -146,11 +147,17 @@ export default {
return feature
})
let gpx = togpx({
let options = {
metadata: {
name: 'Photos from ' + this.title + ' for ' + this.summit.name + ' (' + this.summit.code + ')'
}
}
let gpx = GeoJsonToGpx({
'type': 'FeatureCollection',
'features': features
})
let blob = new Blob([gpx], { type: 'application/gpx+xml' })
}, options)
let gpxString = new XMLSerializer().serializeToString(gpx)
let blob = new Blob([gpxString], { type: 'application/gpx+xml' })
let url = window.URL.createObjectURL(blob)
let link = document.createElement('a')
link.download = 'photos-' + this.summit.code.replace('/', '_') + '-' + this.title + '.gpx'
@ -170,7 +177,8 @@ export default {
}
.photos >>> figure img {
max-height: 128px;
max-width: 256px;
max-width: 300px;
background-color: #e7e7e7;
}
>>> .photo-title {
font-size: 1rem;
@ -205,6 +213,7 @@ export default {
}
.photos >>> figure img {
max-height: 104px;
max-width: 242px;
}
.photo-group {
padding: 0.25rem 0 0 0.5rem;

Wyświetl plik

@ -13,6 +13,7 @@
<tr><th>Activations</th><td>{{ summit.activationCount }}</td></tr>
<tr v-if="summit.activationDate"><th>Last activation</th><td>{{ summit.activationDate | formatActivationDate }} (<router-link :to="makeActivatorLink(summit.activationCall)">{{ summit.activationCall }}</router-link>)</td></tr>
<tr v-if="lastSpot"><th>Last spot</th><td><span v-html="formatTimeDay(lastSpot.timeStamp)" />: <router-link :to="makeActivatorLink(lastSpot.activatorCallsign)">{{ lastSpot.activatorCallsign }}</router-link>, {{ lastSpot.frequency }} <ModeLabel :mode="lastSpot.mode" /></td></tr>
<tr v-if="nextAlert" class="nextAlert"><th>Next alert</th><td><span v-html="formatDateTimeRelative(nextAlert.dateActivated)" />: <router-link :to="makeActivatorLink(nextAlert.activatorCallsign)">{{ nextAlert.activatorCallsign }}</router-link><div v-if="nextAlert.frequency" class="alertFrequencies">{{ nextAlert.frequency }}</div><div v-if="nextAlert.comments" class="alertComments">{{ nextAlert.comments }}</div></td></tr>
</table>
<div class="buttons">
<b-button v-if="!minimizePopup" size="is-small" icon-left="window-close" @click="$emit('close')">Close</b-button>
@ -36,7 +37,8 @@ export default {
name: 'SummitPopup',
props: {
summit: Object,
lastSpot: Object
lastSpot: Object,
nextAlert: Object
},
mixins: [utils, coverphoto],
components: {
@ -97,6 +99,25 @@ export default {
.summitPopup.minimize .summitCode {
display: none;
}
.summitPopup .nextAlert >>> .date-small {
font-size: 100%;
min-width: 0;
}
.summitPopup .alertFrequencies {
font-size: 0.9em;
margin-top: 0.1em;
max-width: 25em;
overflow: hidden;
text-overflow: ellipsis;
}
.summitPopup .alertComments {
font-size: 0.9em;
margin-top: 0.1em;
max-width: 25em;
color: #777;
overflow: hidden;
text-overflow: ellipsis;
}
.photo {
width: 300px;
padding-bottom: 0.5em;

Wyświetl plik

@ -32,8 +32,8 @@
{{ props.row.publicTransport.description }}
</div>
</div>
<article class="routeDescr" v-html="linkifyCoordinates(props.row.description)" />
<div class="author">by {{ props.row.author }}</div>
<article class="routeDescr" v-html="linkifyCoordinates(props.row.htmlDescription ? props.row.htmlDescription : props.row.description)" />
<div class="author">Posted on {{ props.row.postedDate | formatActivationDate }} by {{ props.row.author }}</div>
<div class="track-download" v-if="props.row.track">
<TrackLink :route="props.row" :summit="summit"><font-awesome-icon :icon="['far', 'file-download']" class="fa-icon" /> Download track (.gpx)</TrackLink>
</div>

Wyświetl plik

@ -38,7 +38,7 @@ export default {
mounted () {
if (!localStorage.getItem('swisstopoInfoShown')) {
// Check if we are in Switzerland
axios.get('https://api.sotl.as/my_country')
axios.get(process.env.VUE_APP_API_URL + '/my_country')
.then(response => {
if (response.data.country === 'CH') {
this.active = true

Wyświetl plik

@ -4,10 +4,11 @@
<script>
import tracks from '../mixins/tracks.js'
import utils from '../mixins/utils.js'
export default {
name: 'TrackLink',
mixins: [tracks],
mixins: [tracks, utils],
props: {
route: Object,
summit: Object
@ -42,7 +43,8 @@ export default {
</link>
</metadata>
<trk>
<name>${this.route.title}</name>
<name>${this.escapeHtml(this.route.title)}</name>
<desc>${this.escapeHtml(this.route.description)}</desc>
<src>${this.route.author}</src>
<trkseg>
${trkpts.join('\n')}

Wyświetl plik

@ -15,13 +15,13 @@ import { faCheck, faCheckCircle, faInfoCircle, faExclamationTriangle, faExclamat
faSnowflake, faWindowMinimize, faWindowMaximize, faWindowClose, faExpandArrows, faLocation, faCalendarCheck, faComment, faSpinner,
faBookUser } from '@fortawesome/pro-regular-svg-icons'
import { faMap, faCheckCircle as fasCheckCircle, faChevronCircleDown as fasChevronCircleDown, faChevronCircleUp as fasChevronCircleUp,
faParking, faSquare, faBus, faHiking, faCircle, faCamera, faCameraHome, faVolume, faVolumeMute, faCog, faCaretDown as fasCaretDown, faLocationArrow as fasLocationArrow } from '@fortawesome/pro-solid-svg-icons'
faParking, faSquare, faBus, faHiking, faCircle, faCamera, faCameraHome, faVolume, faVolumeMute, faCog, faCaretDown as fasCaretDown,
faLocationArrow as fasLocationArrow, faInfoCircle as fasInfoCircle } from '@fortawesome/pro-solid-svg-icons'
import { faWikipediaW, faGoogle, faGithub } from '@fortawesome/free-brands-svg-icons'
import { FontAwesomeIcon, FontAwesomeLayers } from '@fortawesome/vue-fontawesome'
import '@/assets/global.css'
import store from './store'
import axios from 'axios'
import { SnackbarProgrammatic as Snackbar } from 'buefy/dist/components/snackbar'
library.add(faCheck, faCheckCircle, faInfoCircle, faExclamationTriangle, faExclamationCircle, faArrowUp, faPlus, faCheckDouble,
faAngleRight, faAngleLeft, faAngleDown, faAngleUp, faEye, faEyeSlash, faCaretUp, faUpload, faLink, faHistory, faThList, faImages,
@ -29,7 +29,8 @@ library.add(faCheck, faCheckCircle, faInfoCircle, faExclamationTriangle, faExcla
faExchange, faGlobe, faCalendarDay, faTrashAlt, faEdit, faClone, farCheckCircle, faArrowsH, faArrowsAlt,
faSnowflake, faWindowMinimize, faWindowMaximize, faWindowClose, faExpandArrows, faLocation, faCalendarCheck, faComment, faSpinner,
faBookUser)
library.add(faMap, fasCheckCircle, fasChevronCircleDown, fasChevronCircleUp, faParking, faSquare, faBus, faHiking, faCircle, faCamera, faCameraHome, faVolume, faVolumeMute, faCog, fasCaretDown, fasLocationArrow)
library.add(faMap, fasCheckCircle, fasChevronCircleDown, fasChevronCircleUp, faParking, faSquare, faBus, faHiking, faCircle, faCamera,
faCameraHome, faVolume, faVolumeMute, faCog, fasCaretDown, fasLocationArrow, fasInfoCircle)
library.add(faWikipediaW, faGoogle, faGithub)
Vue.component('font-awesome-icon', FontAwesomeIcon)
Vue.component('font-awesome-layers', FontAwesomeLayers)
@ -42,6 +43,8 @@ Vue.use(Buefy, {
})
Vue.use(MatchMedia)
let myVue
if (window.performance && performance.navigation.type === 1) {
// Store last reload timestamp so user reloads can be detected despite SSO redirect
sessionStorage.setItem('lastReload', new Date().getTime())
@ -83,8 +86,10 @@ let lastError = null
axios.interceptors.response.use(response => {
return response
}, error => {
if ((!lastError || new Date().getTime() - lastError > 9000) && (!error.response || error.response.status !== 404)) {
Snackbar.open({
if ((!lastError || new Date().getTime() - lastError > 9000) && (!error.response || error.response.status !== 404) && myVue) {
// SnackbarProgrammatic.open doesn't work with Webpack 5
// See https://github.com/buefy/buefy/issues/2299
myVue.$buefy.snackbar.open({
duration: 9000,
message: 'Network or server error while loading data, try again later',
type: 'is-danger',
@ -99,13 +104,14 @@ axios.interceptors.response.use(response => {
})
function startVue () {
new Vue({
myVue = new Vue({
store,
router,
render: h => h(App),
mq: {
mobile: '(max-width: 768px)',
desktop: '(min-width: 1024px)',
widescreen: '(min-width: 1216px)',
fullhd: '(min-width: 1408px)'
}
}).$mount('#app')

14
src/mapsession.js 100644
Wyświetl plik

@ -0,0 +1,14 @@
import axios from 'axios'
let mapSessionReported = false
function reportMapSession () {
if (mapSessionReported) {
return
}
axios.post(process.env.VUE_APP_API_URL + '/mapsession', { type: 'maptiler' })
.catch(() => {})
mapSessionReported = true
}
export default reportMapSession

Wyświetl plik

@ -5,7 +5,7 @@ export default {
mixins: [ssoauth],
methods: {
loadActivations (callsign) {
return axios.get('https://api.sotl.as/activations/' + callsign)
return axios.get(process.env.VUE_APP_API_URL + '/activations/' + callsign)
.then(response => {
return response.data
})
@ -13,20 +13,26 @@ export default {
uploadPhoto (summitCode, file, progress, cancelToken) {
let formData = new FormData()
formData.append('photo', file)
return this.axiosAuth.post('https://api.sotl.as/photos/summits/' + summitCode + '/upload', formData, {
return this.axiosAuth.post(process.env.VUE_APP_API_URL + '/photos/summits/' + summitCode + '/upload', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
onUploadProgress: progress,
cancelToken
})
},
deletePhoto (summitCode, filename) {
return this.axiosAuth.delete('https://api.sotl.as/photos/summits/' + summitCode + '/' + filename)
return this.axiosAuth.delete(process.env.VUE_APP_API_URL + '/photos/summits/' + summitCode + '/' + filename)
},
editPhoto (summitCode, filename, data) {
return this.axiosAuth.post('https://api.sotl.as/photos/summits/' + summitCode + '/' + filename, data)
return this.axiosAuth.post(process.env.VUE_APP_API_URL + '/photos/summits/' + summitCode + '/' + filename, data)
},
reorderPhotos (summitCode, filenames) {
return this.axiosAuth.post('https://api.sotl.as/photos/summits/' + summitCode + '/reorder', { filenames })
return this.axiosAuth.post(process.env.VUE_APP_API_URL + '/photos/summits/' + summitCode + '/reorder', { filenames })
},
loadActivator (userIdOrCallsign) {
return axios.get(process.env.VUE_APP_API_URL + '/activators/' + userIdOrCallsign)
.then(response => {
return response.data
})
}
}
}

Wyświetl plik

@ -1,32 +1,21 @@
import axios from 'axios'
export default {
mounted () {
let mapServerOverride
if (localStorage.getItem('mapServer')) {
mapServerOverride = localStorage.getItem('mapServer')
} else if (sessionStorage.getItem('mapServer')) {
mapServerOverride = sessionStorage.getItem('mapServer')
}
if (mapServerOverride && mapServerOverride !== 'test') {
this.mapServer = mapServerOverride
} else {
axios.get('https://api.sotl.as/map_server')
.then(response => {
if (response.data.mapServer) {
this.mapServer = response.data.mapServer
sessionStorage.setItem('mapServer', response.data.mapServer)
}
})
}
this.initialMapOptions = { ...this.mapOptions }
},
computed: {
mapStyle () {
if (this.mapServer === null) {
return null
if (this.mapType === 'maptiler_outdoor') {
if (this.$store.state.altitudeUnits === 'ft') {
return 'dc9edd90-1320-4fa4-98ba-ad2d4efe5998'
} else {
return '3a0840d2-674e-4630-a70e-8fdb111259b9'
}
} else if (this.mapType === 'maptiler_winter') {
if (this.$store.state.altitudeUnits === 'ft') {
return 'f5400991-e3f4-4734-a941-6be8d26381e7'
} else {
return '5e862436-7ea7-4102-8b56-d35df3a11c07'
}
}
let style = require('../assets/' + this.mapType + '.json')
@ -43,35 +32,25 @@ export default {
}
})
// Patch map server
// Patch MapTiler key
Object.values(style.sources).forEach(source => {
if (source.url) {
source.url = source.url.replace('{mapServer}', this.mapServer)
source.url = source.url.replace('{key}', process.env.VUE_APP_MAPTILER_KEY)
}
})
style.glyphs = style.glyphs.replace('{mapServer}', this.mapServer)
// Patch units
if (this.$store.state.altitudeUnits === 'ft' && this.mapType === 'openmaptiles') {
style.layers.forEach(layer => {
if (layer.id === 'contour_label') {
layer.layout['text-field'] = ['to-string', ['round', ['*', ['get', 'height'], 3.28084]]]
} else if (layer.id === 'summits_names') {
layer.layout['text-field'] = ['concat', ['get', 'name'], '\n', ['get', 'code'], '\n', ['to-string', ['round', ['*', ['get', 'alt'], 3.28084]]], ' ft']
} else if (layer.id === 'summits_inactive_names') {
layer.layout['text-field'] = ['concat', ['get', 'name'], '\n', ['get', 'code'], '\n', ['to-string', ['round', ['*', ['get', 'alt'], 3.28084]]], ' ft\n(inactive)']
}
})
}
style.glyphs = style.glyphs.replace('{key}', process.env.VUE_APP_MAPTILER_KEY)
return style
},
mapType () {
let mapType = this.$store.state.mapType
if (!this.mapTypes[mapType]) {
mapType = 'openmaptiles'
mapType = 'maptiler_outdoor'
}
return mapType
},
mapApiKey () {
return process.env.VUE_APP_MAPTILER_KEY
}
},
methods: {
@ -94,12 +73,57 @@ export default {
},
data () {
return {
mapServer: null,
mapServers: {
'eu': 'Europe (Switzerland)',
'us': 'US (California)'
mapTypes: {
'maptiler_outdoor': {
name: 'MapTiler Outdoor',
difficulty: true,
contours: true,
hillshading: true
},
'maptiler_winter': {
name: 'MapTiler Winter',
contours: true,
hillshading: true
},
'swisstopo': {
name: 'swisstopo (Vector)',
difficulty: true,
contours: true,
hillshading: true,
skiing: true,
snowshoe: true,
slope_classes: true,
wildlife: true
},
'swisstopo_raster': {
name: 'swisstopo (Raster)',
difficulty: true,
skiing: true,
snowshoe: true,
slope_classes: true,
wildlife: true
},
'swisstopo_aerial': {
name: 'swisstopo (Aerial)',
difficulty: true,
skiing: true,
snowshoe: true,
slope_classes: true,
wildlife: true
},
'basemapat': {
name: 'basemap.at'
},
'caltopo': {
name: 'CalTopo'
},
'toposvalbard': {
name: 'TopoSvalbard'
},
'norkart': {
name: 'Norkart'
}
},
mapTypes: { 'openmaptiles': 'OpenMapTiles', 'swisstopo': 'swisstopo (Vector)', 'swisstopo_raster': 'swisstopo (Raster)' },
initialMapOptions: null
}
}

Wyświetl plik

@ -1,7 +1,11 @@
export default {
methods: {
photoSrc (photo, size) {
return 'https://images.sotl.as/photos/' + size + '/' + photo.filename.substring(0, 2) + '/' + photo.filename
if (size === 'original') {
return process.env.VUE_APP_PHOTOS_ORIGINAL_URL + '/' + photo.filename
} else {
return process.env.VUE_APP_PHOTOS_URL + '/' + size + '/' + photo.filename
}
}
}
}

Wyświetl plik

@ -48,8 +48,10 @@ export default {
routes.push({
id: track.hdr_id,
title: track.track_title,
description: '<p>' + this.escapeHtml(track.track_notes) + '</p><p><small>Track imported from <a href="https://www.sotamaps.org" target="_blank">SMP</a></small></p>',
htmlDescription: '<p>' + this.escapeHtml(track.track_notes).replace(/\n/g, '<br />') + '</p><p><small>Track imported from <a href="https://www.sotamaps.org" target="_blank">SMP</a></small></p>',
description: track.track_notes,
author: track.callsign,
postedDate: track.posted_date,
distance,
ascent,
ascentExcludesCounterAscents: (ascent > 0),

Wyświetl plik

@ -1,11 +1,12 @@
import axios from 'axios'
import ssoauth from './ssoauth.js'
import utils from './utils.js'
export default {
mixins: [ssoauth],
mixins: [ssoauth, utils],
methods: {
loadActivations (callsign) {
return axios.get('https://api.sotl.as/activations/' + callsign)
return axios.get(process.env.VUE_APP_API_URL + '/activations/' + callsign)
.then(response => {
return response.data
})

Wyświetl plik

@ -19,7 +19,10 @@ let bands = [
{ from: 900, to: 928, band: '33cm' },
{ from: 1200, to: 1400, band: '23cm' },
{ from: 2300, to: 2450, band: '13cm' },
{ from: 3300, to: 3500, band: '9cm' }
{ from: 3300, to: 3500, band: '9cm' },
{ from: 5600, to: 5925, band: '5cm' },
{ from: 10000, to: 10500, band: '3cm' },
{ from: 24000, to: 24250, band: '1.2cm' }
]
let continents = {
@ -212,6 +215,21 @@ export default {
return undefined
}
},
bandForDbFrequency (dbFrequency) {
return this.bandForFrequency(this.dbFrequencyToMHz(dbFrequency))
},
dbFrequencyToMHz (dbFrequency) {
let matches = /^([0-9.]+)([GM]Hz)$/.exec(dbFrequency)
if (matches) {
let multiplier = 1
if (matches[2] === 'GHz') {
multiplier = 1000
}
return parseFloat(matches[1]) * multiplier
} else {
return dbFrequency
}
},
escapeHtml (unsafe) {
if (unsafe === undefined || unsafe === null) {
return ''

Wyświetl plik

@ -17,11 +17,13 @@ import SotaSpots from './views/SotaSpots.vue'
import RBNSpots from './views/RBNSpots.vue'
import Alerts from './views/Alerts.vue'
import NewPhotos from './views/NewPhotos.vue'
import SolarHistory from './views/SolarHistory.vue'
Vue.use(Router)
let router = new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/',
@ -167,6 +169,10 @@ let router = new Router({
path: '/new_photos',
component: NewPhotos
},
{
path: '/solar_history',
component: SolarHistory
},
{
path: '*',
component: NotFound,

Wyświetl plik

@ -22,13 +22,14 @@ if (altitudeUnits !== 'ft' && altitudeUnits !== 'm') {
let mapType = localStorage.getItem('mapType')
if (!mapType) {
mapType = 'openmaptiles'
mapType = 'maptiler_outdoor'
}
let mapOptions = {
regions: false,
contours: true,
hillshading: true,
az: true,
difficulty: true,
spots: false,
inactive: false,
@ -199,7 +200,7 @@ function loadAlerts (noCache) {
if (noCache) {
params.noCache = 1
}
axios.get('https://api.sotl.as/alerts', { params })
axios.get(process.env.VUE_APP_API_URL + '/alerts', { params })
.then(response => {
store.commit('setAlerts', response.data)
})
@ -208,7 +209,7 @@ function loadAlerts (noCache) {
loadAlerts(false)
setInterval(loadAlerts, ALERT_UPDATE_INTERVAL)
Vue.use(VueNativeSock, 'wss://api.sotl.as/ws', {
Vue.use(VueNativeSock, process.env.VUE_APP_WSS_URL + '/ws', {
format: 'json',
store,
reconnection: true,

Wyświetl plik

@ -9,11 +9,13 @@
<p>Code contributed by: <a href="https://github.com/m1hax">@m1hax</a>, <a href="https://github.com/summitsontheair">@summitsontheair</a>,
<a href="https://github.com/vk3arr">@vk3arr</a>,
Simon G4TJC
Simon G4TJC,
<a href="https://github.com/g84ycm">@g84ycm</a>,
<a href="https://github.com/benmarwick">@benmarwick</a>
</p>
<p>
Summit database © 2002-2021 Summits on the Air.<br />
Summit database © 2002-2024 Summits on the Air.<br />
Summits on the Air, SOTA and the SOTA Logo are trademarks of the Programme.
</p>
@ -32,13 +34,12 @@
</p>
<p>
Icons made by <a href="https://www.flaticon.com/authors/nikita-golubev" title="Nikita Golubev">Nikita Golubev</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> are licensed by <a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a>
Icons made by <a href="https://www.flaticon.com/authors/nikita-golubev" title="Nikita Golubev">Nikita Golubev</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> are licensed by <a href="https://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a>
</p>
<p>Technologies used:
<ul>
<li><a href="https://openmaptiles.org">OpenMapTiles</a></li>
<li><a href="https://docs.mapbox.com/mapbox-gl-js/overview/">Mapbox GL JS</a>
<li><a href="https://maptiler.com/">MapTiler</a></li>
<li><a href="https://nodejs.org/">Node.js</a> server</li>
<li>SPA built with <a href="https://vuejs.org">Vue.js</a>, <a href="https://vuex.vuejs.org">Vuex</a> and <a href="https://router.vuejs.org">Vue Router</a></li>
<li><a href="https://buefy.org">Buefy</a> UI framework</li>

Wyświetl plik

@ -106,7 +106,6 @@
</template>
<script>
import axios from 'axios'
import moment from 'moment'
import utils from '../mixins/utils.js'
import api from '../mixins/api.js'
@ -284,10 +283,15 @@ export default {
// Some padding
let latDiff = maxLat - minLat
let lonDiff = maxLon - minLon
minLat -= (latDiff * 0.1)
maxLat += (latDiff * 0.1)
minLon -= (lonDiff * 0.1)
maxLon += (lonDiff * 0.1)
minLat -= (latDiff * 0.05)
maxLat += (latDiff * 0.05)
minLon -= (lonDiff * 0.05)
maxLon += (lonDiff * 0.05)
minLat = Math.max(Math.min(minLat, 90), -90)
maxLat = Math.max(Math.min(maxLat, 90), -90)
minLon = Math.max(Math.min(minLon, 180), -180)
maxLon = Math.max(Math.min(maxLon, 180), -180)
return [[minLon, minLat], [maxLon, maxLat]]
},
@ -335,10 +339,10 @@ export default {
this.databaseError = false
let loads = []
axios.get('https://api.sotl.as/activators/' + this.callsign)
.then(response => {
if (response) {
this.activator = response.data
this.loadActivator(this.callsign)
.then(activator => {
if (activator) {
this.activator = activator
if (this.activator && this.activator.callsign !== this.callsign) {
this.$router.replace('/activators/' + this.activator.callsign)
return

Wyświetl plik

@ -63,7 +63,7 @@ export default {
methods: {
loadData () {
this.loading = true
axios.get('https://api.sotl.as/activators/search', { params: { q: this.filter, skip: (this.curPage - 1) * this.perPage, limit: this.perPage, sort: this.sortField, sortDirection: this.sortDirection } })
axios.get(process.env.VUE_APP_API_URL + '/activators/search', { params: { q: this.filter, skip: (this.curPage - 1) * this.perPage, limit: this.perPage, sort: this.sortField, sortDirection: this.sortDirection } })
.then(response => {
this.activators = response.data.activators
this.total = response.data.total

Wyświetl plik

@ -3,7 +3,7 @@
<template v-slot:title>Alerts</template>
<template v-slot:title-right>
<div class="action-button">
<b-button type="is-info" icon-left="plus" @click="$refs.alertsList.addAlert()" :disabled="!authenticated">Add</b-button>
<b-button type="is-info" icon-left="plus" @click="$refs.alertsList.addAlert()">Add</b-button>
</div>
</template>

Wyświetl plik

@ -17,7 +17,7 @@
<div class="column">
<b-table default-sort="code" :narrowed="true" :striped="true" :data="filteredRegions" :mobile-cards="false">
<template slot-scope="props">
<b-table-column field="code" label="Code" class="nowrap" sortable>
<b-table-column field="code" label="Identifier" class="nowrap" sortable>
<router-link :to="regionLink(props.row)">{{ props.row.code }}</router-link>
</b-table-column>
<b-table-column field="name" label="Name" sortable>
@ -79,7 +79,7 @@ export default {
},
loadAssociation () {
this.loadingComponent = this.$buefy.loading.open({ canCancel: true })
axios.get('https://api.sotl.as/associations/' + this.associationCode)
axios.get(process.env.VUE_APP_API_URL + '/associations/' + this.associationCode)
.then(response => {
this.association = response.data
document.title = this.association.name + ' (' + this.associationCode + ') - SOTLAS'
@ -104,7 +104,7 @@ export default {
})
},
exportUrlPrefix () {
return `https://api.sotl.as/geoexport/associations/${this.associationCode}`
return process.env.VUE_APP_API_URL + '/geoexport/associations/' + this.associationCode
},
myActivationsPerRegion () {
if (!this.$store.state.myActivatedSummits) {

Wyświetl plik

@ -13,7 +13,7 @@
</b-field>
<b-table class="auto-width" default-sort="code" :narrowed="true" :striped="true" :data="filteredAssociations" :mobile-cards="false">
<template slot-scope="props">
<b-table-column field="code" label="Code" class="nowrap" sortable>
<b-table-column field="code" label="Identifier" class="nowrap" sortable>
<router-link :to="associationLink(props.row)">{{ props.row.code }}</router-link>
</b-table-column>
<b-table-column field="name" label="Name" sortable>
@ -49,7 +49,7 @@ export default {
mounted () {
document.title = 'Associations - SOTLAS'
this.loadingComponent = this.$buefy.loading.open({ canCancel: true })
axios.get('https://api.sotl.as/associations/all')
axios.get(process.env.VUE_APP_API_URL + '/associations/all')
.then(response => {
this.associations = response.data
this.loadingComponent.close()

Wyświetl plik

@ -1,6 +1,6 @@
<template>
<div class="map-layout" ref="mapLayout">
<MglMap v-if="showMap && mapStyle" :mapStyle="mapStyle" :bounds.sync="bounds" :fitBoundsOptions="fitBoundsOptions" :center="center" :zoom="zoom" :dragRotate="false" :attributionControl="false" class="map" @load="onMapLoaded" @click="onMapClicked" @contextmenu="onMapRightClicked">
<MglMap v-if="showMap && mapStyle" :apiKey="mapApiKey" :mapStyle="mapStyle" :bounds.sync="bounds" :fitBoundsOptions="fitBoundsOptions" :center="center" :zoom="zoom" :dragRotate="false" :attributionControl="false" class="map" @load="onMapLoaded" @click="onMapClicked" @contextmenu="onMapRightClicked">
<MglGeolocateControl :positionOptions="{ enableHighAccuracy: true }" :fitBoundsOptions="{ maxZoom: 12.5 }" :trackUserLocation="true" position="top-right" />
<MglNavigationControl position="top-right" :showCompass="false" />
<MglScaleControl position="bottom-left" />
@ -8,7 +8,7 @@
<!-- Note: these are not true Mapbox GL controls that get added via addControl(), as those don't mix well with Vue.js templating.
Instead, we simply put all our custom non-Mapbox controls in the top left corner where they don't clash with any builtin controls. -->
<div class="mapboxgl-ctrl-top-left">
<div class="maplibregl-ctrl-top-left">
<MapFilterControl ref="filterControl" position="top-left" @startFiltering="filtering = true" @stopFiltering="filtering = false" />
<MapOptionsControl ref="optionsControl" position="top-left" />
<MapDownloadControl position="top-left" />
@ -20,7 +20,7 @@
</div>
</MglPopup>
<SummitPopup v-if="summit" :summit="summit" :lastSpot="lastSummitSpot" @close="onPopupClosed" />
<SummitPopup v-if="summit" :summit="summit" :lastSpot="lastSummitSpot" :nextAlert="nextSummitAlert" @close="onPopupClosed" />
<MapRoute v-for="route in persistentRoutes" :key="route.id" :route="route" />
@ -30,20 +30,20 @@
<MapWebcams v-if="mapOptions.webcams" />
</MglMap>
<div v-if="browserNotSupported" class="browser-not-supported">Your browser does not support WebGL, which is required to render this map.</div>
<div v-if="zoomWarning" class="zoom-warning">Zoom in to see all filtered/spotted summits</div>
<SwisstopoInfo />
<BasemapAtInfo />
<b-loading :is-full-page="false" :active="filtering || !showMap || !mapStyle" />
</div>
</template>
<script>
import axios from 'axios'
import mapboxgl from 'mapbox-gl'
import utils from '../mixins/utils.js'
import smptracks from '../mixins/smptracks.js'
import mapstyle from '../mixins/mapstyle.js'
import longtouch from '../mixins/longtouch.js'
import reportMapSession from '../mapsession.js'
import { MglMap, MglPopup, MglNavigationControl, MglGeolocateControl, MglScaleControl, MglAttributionControl } from 'vue-mapbox'
import MapFilterControl from '../components/MapFilterControl.vue'
@ -56,21 +56,18 @@ import MapInfoPopup from '../components/MapInfoPopup.vue'
import MapDraw from '../components/MapDraw.vue'
import MapWebcams from '../components/MapWebcams.vue'
import SwisstopoInfo from '../components/SwisstopoInfo.vue'
import BasemapAtInfo from '../components/BasemapAtInfo.vue'
export default {
name: 'Map',
components: {
MglMap, MglPopup, MglNavigationControl, MglGeolocateControl, MglScaleControl, MglAttributionControl, MapFilterControl, MapOptionsControl, MapDownloadControl, LoadingRing, SummitPopup, MapRoute, MapInfoPopup, MapDraw, MapWebcams, SwisstopoInfo
MglMap, MglPopup, MglNavigationControl, MglGeolocateControl, MglScaleControl, MglAttributionControl, MapFilterControl, MapOptionsControl, MapDownloadControl, LoadingRing, SummitPopup, MapRoute, MapInfoPopup, MapDraw, MapWebcams, SwisstopoInfo, BasemapAtInfo
},
mixins: [utils, smptracks, mapstyle, longtouch],
created () {
this.map = null
},
mounted () {
if (!mapboxgl.supported()) {
this.browserNotSupported = true
}
// Check for summit code or coordinates first; if present, start map right there
if (this.$route.params.summitCode) {
this.fetchSummit(this.$route.params.summitCode)
@ -101,7 +98,7 @@ export default {
} catch (e) {}
this.showMap = true
} else {
axios.get('https://api.sotl.as/my_coordinates')
axios.get(process.env.VUE_APP_API_URL + '/my_coordinates')
.then(response => {
if (response.data.latitude && response.data.longitude) {
this.center = [response.data.longitude, response.data.latitude]
@ -133,7 +130,6 @@ export default {
summit: null,
leavingRoute: false,
zoomWarning: false,
browserNotSupported: false,
filtering: false,
infoCoordinates: null,
persistentRoutes: []
@ -194,6 +190,28 @@ export default {
return null
}
},
nextSummitAlert () {
if (!this.summit) {
return null
}
let alerts = this.$store.state.alerts.filter(alert => {
return (alert.summit.code === this.summit.code)
}).sort((a, b) => {
if (a.dateActivated > b.dateActivated) {
return 1
} else if (a.dateActivated < b.dateActivated) {
return -1
} else {
return 0
}
})
if (alerts.length > 0) {
return alerts[0]
} else {
return null
}
},
mapOptions () {
return this.$store.state.mapOptions
}
@ -202,7 +220,7 @@ export default {
onMapLoaded (event) {
this.map = event.map
this.map.touchZoomRotate.disableRotation();
['summits_circles', 'summits_inactive_circles'].forEach(layer => {
['summits_circles_all', 'summits_circles', 'summits_inactive_circles'].forEach(layer => {
this.map.on('mouseenter', layer, () => {
if (!this.$refs.draw.isDrawing()) {
this.map.getCanvas().style.cursor = 'pointer'
@ -214,6 +232,7 @@ export default {
})
this.updateLayers(this.map)
this.map.setLayoutProperty('summits_circles_all', 'visibility', 'visible')
this.installLongTouchHandler(this.map, (e) => {
this.infoCoordinates = {
@ -222,6 +241,8 @@ export default {
}
})
this.updateRoute()
reportMapSession()
},
onMapClicked (event) {
if (this.$refs.draw.isDrawing() || event.mapboxEvent.originalEvent.hitMarker) {
@ -231,7 +252,7 @@ export default {
// Search for summit circles with some padding/fuzz to make it easier to hit on mobile devices
let point = event.mapboxEvent.point
let bbox = [[point.x - this.clickFuzz, point.y - this.clickFuzz], [point.x + this.clickFuzz, point.y + this.clickFuzz]]
let features = this.map.queryRenderedFeatures(bbox, { layers: ['summits_circles', 'summits_inactive_circles'] })
let features = this.map.queryRenderedFeatures(bbox, { layers: ['summits_circles_all', 'summits_circles', 'summits_inactive_circles'] })
if (features.length === 0) {
// User probably clicked outside any features; close any controls
@ -324,7 +345,7 @@ export default {
})
},
fetchSummit (summitCode) {
return axios.get('https://api.sotl.as/summits/' + summitCode)
return axios.get(process.env.VUE_APP_API_URL + '/summits/' + summitCode)
.then(response => {
let summit = response.data
summit.photo = null
@ -332,7 +353,7 @@ export default {
})
},
fetchAssociation (associationCode) {
return axios.get('https://api.sotl.as/associations/' + associationCode)
return axios.get(process.env.VUE_APP_API_URL + '/associations/' + associationCode)
.then(response => {
return response.data
})
@ -432,7 +453,7 @@ export default {
bottom: 0;
left: 0;
}
.map >>> .mapboxgl-popup {
.map >>> .maplibregl-popup {
max-width: 600px !important;
}
.loading-ring-wrapper {
@ -449,13 +470,4 @@ export default {
text-align: center;
opacity: 0.9;
}
.browser-not-supported {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
background-color: #fdc5c9;
padding: 0.2em 0.5em;
border-radius: 0.5em;
}
</style>

Wyświetl plik

@ -64,7 +64,7 @@ export default {
if (this.selectedAssociations.length > 0) {
associations = this.selectedAssociations.join('|')
}
axios.get('https://api.sotl.as/summits/recent_photos/' + associations + '/' + this.days, { params: recentPhotosParams })
axios.get(process.env.VUE_APP_API_URL + '/summits/recent_photos/' + associations + '/' + this.days, { params: recentPhotosParams })
.then(response => {
this.loadingComponent.close()
this.summits = response.data.slice(0, -1)
@ -72,7 +72,7 @@ export default {
})
},
loadAssociations () {
axios.get('https://api.sotl.as/associations/all')
axios.get(process.env.VUE_APP_API_URL + '/associations/all')
.then(response => {
this.associations = response.data
})

Wyświetl plik

@ -6,7 +6,7 @@
<section class="section">
<div class="container">
<b-message title="Not Found" type="is-danger">
The page, summit, association or region that you requested cannot be found.
The callsign, summit, association, region or page that you requested cannot be found.
</b-message>
</div>
</section>

Wyświetl plik

@ -74,7 +74,7 @@ export default {
})
},
exportUrlPrefix () {
return `https://api.sotl.as/geoexport/regions/${this.regionCode}`
return process.env.VUE_APP_API_URL + '/geoexport/regions/' + this.regionCode
},
exportUrlParams () {
return (this.showInactive ? { inactive: 1 } : {})
@ -101,6 +101,8 @@ export default {
},
watch: {
regionCode () {
this.association = {}
this.summits = []
this.loadRegion()
},
showActivatedThisYear () {
@ -123,7 +125,7 @@ export default {
loadRegion () {
let loads = []
this.loadingComponent = this.$buefy.loading.open({ canCancel: true })
loads.push(axios.get('https://api.sotl.as/associations/' + this.associationCode)
loads.push(axios.get(process.env.VUE_APP_API_URL + '/associations/' + this.associationCode)
.then(response => {
this.association = response.data
document.title = this.region.name + ' (' + this.associationCode + '/' + this.region.code + ') - SOTLAS'
@ -134,7 +136,7 @@ export default {
}
}))
loads.push(axios.get('https://api.sotl.as/regions/' + this.regionCode)
loads.push(axios.get(process.env.VUE_APP_API_URL + '/regions/' + this.regionCode)
.then(response => {
let now = moment()
if (response.data.length === 0) {

Wyświetl plik

@ -78,12 +78,12 @@ export default {
let loads = []
let q = this.$route.query.q.trim()
this.loadingComponent = this.$buefy.loading.open({ canCancel: true })
loads.push(axios.get('https://api.sotl.as/activators/search', { params: { q, limit: this.limit } })
loads.push(axios.get(process.env.VUE_APP_API_URL + '/activators/search', { params: { q, limit: this.limit } })
.then(response => {
this.activators = response.data.activators
}))
loads.push(axios.get('https://api.sotl.as/summits/search', { params: { q, limit: this.limit } })
loads.push(axios.get(process.env.VUE_APP_API_URL + '/summits/search', { params: { q, limit: this.limit } })
.then(response => {
let now = moment()
response.data.forEach(summit => {

Wyświetl plik

@ -11,11 +11,6 @@
<b-radio v-model="units" native-value="ft">Imperial (ft/mi)</b-radio>
</b-field>
</b-field>
<b-field label="Map server" message="Choosing the closest server can help increase map loading performance.">
<b-select v-model="mapServerSelect">
<option v-for="(v, k) in mapServers" :value="k" :key="k">{{ v }}</option>
</b-select>
</b-field>
<b-field label="Spot default comments">
<b-input v-model="spotDefaultComments" type="text" maxlength="60" />
</b-field>
@ -40,15 +35,6 @@ export default {
document.title = 'Settings - SOTLAS'
},
computed: {
mapServerSelect: {
get () {
return this.mapServer
},
set (newMapServer) {
localStorage.setItem('mapServer', newMapServer)
location.reload()
}
},
units: {
get () {
return this.$store.state.altitudeUnits

Wyświetl plik

@ -0,0 +1,87 @@
<template>
<PageLayout>
<template v-slot:title>Solar Data</template>
<template>
<section class="section">
<div class="container content">
<LineChart class="solar-chart" v-if="solarHistory !== null" :data="solarHistory" labelField="dateFormatted" valueField="sfi" valueFieldB="r" name="SFI" nameB="SN" :xIsSeries="true" :regionFill="false" spline="1" height="400" />
<BarChart class="solar-chart" v-if="solarHistory !== null" :data="solarHistory" labelField="dateFormatted" valueField="k" name="K" :xIsSeries="true" spline="1" height="200" :spaceRatio="0.5" :colors="['blue']" />
</div>
</section>
</template>
</PageLayout>
</template>
<script>
import axios from 'axios'
import moment from 'moment'
import PageLayout from '../components/PageLayout.vue'
import LineChart from '../components/LineChart.vue'
import BarChart from '../components/BarChart.vue'
export default {
name: 'SolarHistory',
components: { PageLayout, LineChart, BarChart },
methods: {
loadHistory () {
// Fetch data from last 30 days
axios.get(process.env.VUE_APP_API_URL + '/solardata/history/720')
.then(response => {
this.loadingComponent.close()
// Average data per day
let dataPerDay = {}
response.data.forEach(ent => {
if (!dataPerDay[ent.date]) {
dataPerDay[ent.date] = {
sfi: ent.sfi,
r: ent.r,
k: ent.k,
count: 1
}
} else {
dataPerDay[ent.date].sfi += ent.sfi
dataPerDay[ent.date].r += ent.r
dataPerDay[ent.date].k += ent.k
dataPerDay[ent.date].count++
}
})
let chartData = []
Object.entries(dataPerDay).forEach(([date, ent]) => {
chartData.push({
date,
dateFormatted: moment.utc(date).format('D MMM'),
sfi: Math.round(ent.sfi / ent.count),
r: Math.round(ent.r / ent.count),
k: Math.round(ent.k / ent.count)
})
})
this.solarHistory = chartData.sort((a, b) => {
if (a.date < b.date) {
return -1
} else if (a.date > b.date) {
return 1
} else {
return 0
}
})
})
this.loadingComponent = this.$buefy.loading.open({ canCancel: true })
}
},
mounted () {
document.title = 'Solar Data History - SOTLAS'
this.loadHistory()
},
data () {
return {
solarHistory: null
}
}
}
</script>

Wyświetl plik

@ -20,7 +20,14 @@
<p class="subtitle is-size-7-mobile">
<span class="summit-info"><strong>{{ summit.code }}</strong></span>
<span class="summit-info"><AltitudeLabel :altitude="summit.altitude" /></span>
<span class="summit-info"><SummitPointsLabel class="points" :points="summit.points" :bonus="summit.bonusPoints" /> {{ summit.points > 1 ? 'points' : 'point' }}</span>
<span v-if="bonusSeason" class="summit-info">
<b-tooltip class="season-tooltip" type="is-light" :position="$mq.mobile ? 'is-bottom' : 'is-right'" :label="bonusSeason">
<SummitPointsLabel class="points" :points="summit.points" :bonus="summit.bonusPoints" />
</b-tooltip> {{ summit.points > 1 ? 'points' : 'point' }}
</span>
<span v-else class="summit-info">
<SummitPointsLabel class="points" :points="summit.points" :bonus="summit.bonusPoints" /> {{ summit.points > 1 ? 'points' : 'point' }}
</span>
<span v-if="activations !== null" class="summit-info"><font-awesome-icon :icon="['far', 'chevron-circle-up']" class="faicon" /> {{ activations.length }} {{ activations.length === 1 ? 'activation' : 'activations' }}<span v-if="myActivations && myActivations.length > 0"> ({{ myActivations.length }} by me)</span></span>
<span v-if="myChases !== null && myChases.length > 0" class="summit-info"><font-awesome-icon :icon="['far', 'chevron-circle-down']" class="faicon" /> {{ myChases.length }} {{ myChases.length === 1 ? 'chase' : 'chases' }} by me</span>
<span v-if="isComplete" class="summit-info"><font-awesome-icon :icon="['far', 'check-double']" class="faicon" /> Complete</span>
@ -53,14 +60,16 @@
<div>Coordinates: <Coordinates v-if="summit.coordinates" :latitude="summit.coordinates.latitude" :longitude="summit.coordinates.longitude" :altitude="summit.altitude" :reference="summit.code" /></div>
<div>Locator: <span class="locator">{{ locator }}</span></div>
<div v-if="$keycloak && $keycloak.authenticated && summit.coordinates">Distance/Bearing: <Bearing :latitude="summit.coordinates.latitude" :longitude="summit.coordinates.longitude" /></div>
<div v-if="firstActivations">First activation:
<span v-for="(activator, index) in firstActivations.activators" :key="activator.userId"><router-link :to="makeActivatorLinkUserId(activator.userId)"><strong>{{ activator.callsign }}</strong></router-link>{{ index !== firstActivations.activators.length - 1 ? ' & ' : '' }}</span>
<div v-if="firstActivations">
<span v-if="firstActivations.activators.length == 1">First activation: </span>
<span v-else>First day's activations: </span>
<span v-for="(activator, index) in firstActivations.activators" :key="activator.userId"><FirstActivator :callsign="activator.callsign" :userId="activator.userId" />{{ index !== firstActivations.activators.length - 1 ? ' & ' : '' }}</span>
<span class="has-text-grey"> on {{ firstActivations.date | formatActivationDate }}</span></div>
<SummitAttributes :attributes="summit.attributes" />
<template v-if="resources.length > 0">
<h6 class="title is-6">Resources</h6>
<h6 class="title is-6">Resources<span v-if="$keycloak && $keycloak.authenticated" class="add-article is-size-7-mobile">(<a :href="addArticleLink">+ Article</a>)</span><span v-else class="add-article is-size-7-mobile">(<span class="disabled">+ Article</span>)</span></h6>
<ResourceList :resources="resources" />
</template>
</div>
@ -122,6 +131,7 @@
<script>
import axios from 'axios'
import api from '../mixins/api.js'
import utils from '../mixins/utils.js'
import smptracks from '../mixins/smptracks.js'
import coverphoto from '../mixins/coverphoto.js'
@ -144,6 +154,7 @@ import SpotsList from '../components/SpotsList.vue'
import AlertsList from '../components/AlertsList.vue'
import EditAlert from '../components/EditAlert.vue'
import EditSpot from '../components/EditSpot.vue'
import FirstActivator from '../components/FirstActivator.vue'
import HikrIcon from '../assets/hikr.png'
import SACIcon from '../assets/sac.png'
import SotatrailsIcon from '../assets/sotatrails.png'
@ -155,9 +166,9 @@ export default {
summitCode: String
},
components: {
SummitDatabasePageLayout, MiniMap, SummitActivations, SummitAttributes, ResourceList, SummitRoutes, SummitPhotos, SummitVideos, PhotosUploader, Coordinates, Bearing, SummitPointsLabel, AltitudeLabel, SpotsList, AlertsList, EditAlert, EditSpot
SummitDatabasePageLayout, MiniMap, SummitActivations, SummitAttributes, ResourceList, SummitRoutes, SummitPhotos, SummitVideos, PhotosUploader, Coordinates, Bearing, SummitPointsLabel, AltitudeLabel, SpotsList, AlertsList, EditAlert, EditSpot, FirstActivator
},
mixins: [utils, smptracks, coverphoto],
mixins: [utils, api, smptracks, coverphoto],
computed: {
locator () {
if (!this.summit.coordinates) {
@ -307,6 +318,9 @@ export default {
}
})
return videos
},
addArticleLink () {
return 'https://summits.sota.org.uk/article/new/' + this.summit.code
}
},
watch: {
@ -342,10 +356,10 @@ export default {
}
// Make a dummy POST to the summit URL to invalidate the browser's cache for future page loads
axios.post('https://api.sotl.as/summits/' + this.summitCode)
axios.post(process.env.VUE_APP_API_URL + '/summits/' + this.summitCode)
}
loads.push(axios.get('https://api.sotl.as/summits/' + this.summitCode, options)
loads.push(axios.get(process.env.VUE_APP_API_URL + '/summits/' + this.summitCode, options)
.then(response => {
this.summit = response.data
document.title = this.summit.name + ' (' + this.summit.code + ') - SOTLAS'
@ -356,7 +370,7 @@ export default {
}
}))
loads.push(axios.get('https://api.sotl.as/associations/' + this.summitCode.substr(0, this.summitCode.indexOf('/')))
loads.push(axios.get(process.env.VUE_APP_API_URL + '/associations/' + this.summitCode.substr(0, this.summitCode.indexOf('/')))
.then(response => {
this.association = response.data
}))
@ -379,6 +393,15 @@ export default {
})
}))
loads.push(axios.get('https://api-db2.sota.org.uk/summits/history/' + this.summitCode)
.then(response => {
if (response.data.BonusPoints > 0) {
this.bonusSeason = '+ ' + response.data.BonusSeason
} else {
this.bonusSeason = null
}
}))
if (this.myUserId) {
loads.push(axios.get('https://api2.sota.org.uk/api/qsos/user-chases-by-summit/' + this.summitCode + '/' + this.myUserId)
.then(response => {
@ -395,9 +418,9 @@ export default {
this.loadingComponent = this.$buefy.loading.open({ canCancel: false })
// Make a dummy POST to the summit URL to invalidate the browser's cache for future page loads
axios.post('https://api.sotl.as/summits/' + this.summitCode)
axios.post(process.env.VUE_APP_API_URL + '/summits/' + this.summitCode)
axios.get('https://api.sotl.as/summits/' + this.summitCode, { params: { t: new Date().getTime() } })
axios.get(process.env.VUE_APP_API_URL + '/summits/' + this.summitCode, { params: { t: new Date().getTime() } })
.then(response => {
this.summit = response.data
})
@ -413,9 +436,21 @@ export default {
},
routeDetailsOpen (route) {
this.$set(route, 'highlight', true)
this.routes.forEach(curRoute => {
if (curRoute.highlight !== true) {
this.$set(curRoute, 'highlight', false)
}
})
},
routeDetailsClose (route) {
this.$set(route, 'highlight', false)
// If all route highlights are false, set them all to null
if (this.routes.every(curRoute => curRoute.highlight === false)) {
this.routes.forEach(curRoute => {
this.$set(curRoute, 'highlight', null)
})
}
},
mapReposition (coordinates) {
if (coordinates) {
@ -443,7 +478,8 @@ export default {
isAddAlertActive: false,
isAddSpotActive: false,
enlargeMap: false,
alwaysLoadWikipedia: true
alwaysLoadWikipedia: true,
bonusSeason: null
}
}
}
@ -457,7 +493,7 @@ export default {
}
@media (min-width: 769px) {
.map.enlarge {
height: calc(100vh - 20rem);
height: calc(100vh - 16rem);
}
}
@media (max-width: 768px) {
@ -556,7 +592,7 @@ export default {
color: #777;
text-align: right;
}
>>> .mapboxgl-canvas-container.mapboxgl-interactive {
>>> .maplibregl-canvas-container.maplibregl-interactive {
cursor: auto;
}
.uploader-placeholder {
@ -571,4 +607,16 @@ export default {
.uploader-placeholder .fa-images {
margin-right: 0.5em;
}
.add-article {
font-weight: normal;
font-size: 90%;
margin-left: 0.5em;
}
.add-article .disabled {
color: #b5b5b5;
cursor: not-allowed;
}
.season-tooltip {
cursor: default;
}
</style>

Wyświetl plik

@ -1,7 +1,7 @@
const webpack = require('webpack')
const GitRevisionPlugin = require('git-revision-webpack-plugin')
const { GitRevisionPlugin } = require('git-revision-webpack-plugin')
const gitRevisionPlugin = new GitRevisionPlugin()
const gitRevisionPlugin = new GitRevisionPlugin({ branch: true })
module.exports = {
productionSourceMap: false,
@ -14,6 +14,14 @@ module.exports = {
'COMMITHASH': JSON.stringify(gitRevisionPlugin.commithash()),
'BRANCH': JSON.stringify(gitRevisionPlugin.branch())
})
]
}
],
resolve: {
fallback: {
fs: false,
path: false
},
exportsFields: [] // Needed because @maptiler/sdk uses "import" instead of "style" on the .css export in its package.json; see also https://github.com/webpack/webpack/issues/9509#issuecomment-1915084026
}
},
publicPath: process.env.PUBLIC_PATH
}