From 0396bf30a5059488156112381e22d79eaf6b3c65 Mon Sep 17 00:00:00 2001 From: Dominik Hebeler <dominik@suma-ev.de> Date: Tue, 6 Feb 2024 15:22:21 +0100 Subject: [PATCH] add more controls back to the map --- app/resources/js/GpsManager.js | 8 +-- app/resources/js/maps/Maplibre.js | 17 ++++- app/resources/js/maps/MetaGerMap.js | 3 + app/resources/js/maps/Openlayers.js | 31 +++++++- .../js/openlayers/GeolocationControl.js | 50 +++++++++++++ .../js/openlayers/NavigationControl.js | 30 ++++++++ app/resources/less/map.less | 4 +- app/resources/less/openlayers/controls.less | 71 +++++++++++++++++++ app/resources/views/map.blade.php | 43 +++++------ app/webpack.mix.js | 5 +- 10 files changed, 227 insertions(+), 35 deletions(-) create mode 100644 app/resources/js/openlayers/GeolocationControl.js create mode 100644 app/resources/js/openlayers/NavigationControl.js create mode 100644 app/resources/less/openlayers/controls.less diff --git a/app/resources/js/GpsManager.js b/app/resources/js/GpsManager.js index 22631f9..80aeffe 100644 --- a/app/resources/js/GpsManager.js +++ b/app/resources/js/GpsManager.js @@ -36,9 +36,9 @@ export class GpsManager { this.last_location = location; success_callback(location); return "localstorage"; - } else if (map.androidConnector.is_connected) { + } else if (androidConnector.is_connected) { // Android App is connected. We can use the devices Geolocation - return map.androidConnector.watchPosition( + return androidConnector.watchPosition( (location) => { this.last_location = location; success_callback(location); @@ -61,8 +61,8 @@ export class GpsManager { clearWatch(id) { if (id == "localstorage") { window.removeEventListener("storage", this.#watch_callback); - } else if (map.androidConnector.is_connected) { - map.androidConnector.clearWatch(id); + } else if (androidConnector.is_connected) { + androidConnector.clearWatch(id); } else { navigator.geolocation.clearWatch(id); } diff --git a/app/resources/js/maps/Maplibre.js b/app/resources/js/maps/Maplibre.js index de11ce0..8c5fff8 100644 --- a/app/resources/js/maps/Maplibre.js +++ b/app/resources/js/maps/Maplibre.js @@ -1,6 +1,6 @@ import { config } from "../Config"; import { MetaGerMap } from "./MetaGerMap"; -import { LngLat, Map, setRTLTextPlugin } from "maplibre-gl"; +import { LngLat, Map, NavigationControl, setRTLTextPlugin } from "maplibre-gl"; export class Maplibre extends MetaGerMap { /** @type {Map} */ @@ -13,12 +13,19 @@ export class Maplibre extends MetaGerMap { }; #layer_types = ["fill", "line", "point"]; - #symbol_types = ["marker"]; + + #navigationControl = null; constructor() { super(); setRTLTextPlugin(`${this._tileserver_host}/mapbox-gl-rtl-text.js`); + this.#navigationControl = new NavigationControl({ + showCompass: true, + showZoom: true, + visualizePitch: true + }); + if (config.init.bbox != null) { this.#map_params.bounds = config.init.bbox; } else { @@ -37,7 +44,7 @@ export class Maplibre extends MetaGerMap { // Marker Icon let image = await this._map.loadImage("/img/marker-icon.png"); this._map.addImage("result-marker", image.data); - + this.#addControls(); return new Promise((resolve, reject) => { if (!this._map.loaded()) { this._map.once("load", (e) => { @@ -49,6 +56,10 @@ export class Maplibre extends MetaGerMap { }); } + #addControls() { + this._map.addControl(this.#navigationControl, "bottom-left"); + } + getBounds() { return this._map.getBounds(); } diff --git a/app/resources/js/maps/MetaGerMap.js b/app/resources/js/maps/MetaGerMap.js index bc1c7c6..d5b7cb2 100644 --- a/app/resources/js/maps/MetaGerMap.js +++ b/app/resources/js/maps/MetaGerMap.js @@ -14,6 +14,9 @@ export class MetaGerMap { // The map object of the implementation _map = null; + _controls = { + zoomControl: null, + } constructor() { if (this.constructor == Map) { diff --git a/app/resources/js/maps/Openlayers.js b/app/resources/js/maps/Openlayers.js index 14891ac..f202262 100644 --- a/app/resources/js/maps/Openlayers.js +++ b/app/resources/js/maps/Openlayers.js @@ -18,6 +18,12 @@ import VectorSource from "ol/source/Vector"; import Stroke from "ol/style/Stroke"; import Icon from "ol/style/Icon"; import Text from "ol/style/Text"; +import Zoom from "ol/control/Zoom"; +import Rotate from "ol/control/Rotate"; +import Attribution from "ol/control/Attribution"; +import { NavigationControl } from "../openlayers/NavigationControl"; +import ScaleLine from "ol/control/ScaleLine"; +import { GeolocationControl } from "../openlayers/GeolocationControl"; export class Openlayers extends MetaGerMap { /** @type {Map} */ @@ -46,16 +52,19 @@ export class Openlayers extends MetaGerMap { useGeographic(); this._map = new Map({ target: "map", + controls: [], layers: [ new TileLayer({ source: new XYZ({ extent: [-180, -90, 180, 90], url: response.tiles[0], - tilesize: [512, 512] + tilesize: [512, 512], + attributions: response.attribution, }), + preload: Infinity, minZoom: response.minzoom, maxZoom: response.maxzoom, - attribution: response.attribution, + }) ], view: new View({ @@ -66,6 +75,7 @@ export class Openlayers extends MetaGerMap { }) }); + this.#addControls(); if (config.init.bbox != null) { this._map .getView() @@ -87,6 +97,23 @@ export class Openlayers extends MetaGerMap { }); } + #addControls() { + this._controls.zoomControl = new Zoom({ className: "mg-ol-control-zoom" }); + this._map.addControl(this._controls.zoomControl); + + this._controls.geolocationControl = new GeolocationControl(); + this._map.addControl(this._controls.geolocationControl); + + this._controls.attributionControl = new Attribution({ collapsible: true }); + this._map.addControl(this._controls.attributionControl); + + this._controls.navigationControl = new NavigationControl(); + this._map.addControl(this._controls.navigationControl); + + this._controls.scaleControl = new ScaleLine(); + this._map.addControl(this._controls.scaleControl); + } + /** * * @param {import("maplibre-gl").LngLatBounds} bounds diff --git a/app/resources/js/openlayers/GeolocationControl.js b/app/resources/js/openlayers/GeolocationControl.js new file mode 100644 index 0000000..3c75fb3 --- /dev/null +++ b/app/resources/js/openlayers/GeolocationControl.js @@ -0,0 +1,50 @@ +import Control from "ol/control/Control"; +import { gpsManager } from "../GpsManager"; + +export class GeolocationControl extends Control { + state = "off"; + + watch_id = null; + + constructor(opt_options) { + const options = opt_options || {}; + + let container = document.createElement("div"); + container.classList.add("control-geolocation", "off", "ol-unselectable", "ol-control"); + + let button = document.createElement("button"); + button.textContent = "⌖"; + container.appendChild(button); + + super({ + element: container, + target: options.target + }); + + button.onclick = e => { + container.classList.remove(this.state); + switch (this.state) { + case "off": + this.state = "locked"; + this.watchPosition(); + break; + case "locked": + this.state = "on"; + break; + case "on": + this.state = "off"; + break; + + } + container.classList.add(this.state); + } + } + + watchPosition() { + this.watch_id = gpsManager.watchPosition(this.watch_position_callback.bind(this)); + } + + watch_position_callback(location) { + console.log(location); + } +} \ No newline at end of file diff --git a/app/resources/js/openlayers/NavigationControl.js b/app/resources/js/openlayers/NavigationControl.js new file mode 100644 index 0000000..1f7eaec --- /dev/null +++ b/app/resources/js/openlayers/NavigationControl.js @@ -0,0 +1,30 @@ +import Control from "ol/control/Control"; + +export class NavigationControl extends Control { + constructor(opt_options) { + const options = opt_options || {}; + + let container = document.createElement("div"); + container.classList.add("nav-opener", "ol-unselectable", "ol-control"); + + let button = document.createElement("button"); + button.textContent = "≡"; + container.appendChild(button); + + button.onclick = e => { + let opener = document.querySelector("#nav-opener"); + if (opener) { + if (opener.checked) { + opener.checked = false; + } else { + opener.checked = true; + } + } + } + + super({ + element: container, + target: options.target + }); + } +} \ No newline at end of file diff --git a/app/resources/less/map.less b/app/resources/less/map.less index 601c959..89c27f8 100644 --- a/app/resources/less/map.less +++ b/app/resources/less/map.less @@ -1 +1,3 @@ -@import "../../node_modules/leaflet/dist/leaflet.css"; +@import "../../node_modules/maplibre-gl/dist/maplibre-gl.css"; +@import "../../node_modules/ol/ol.css"; +@import "./openlayers/controls.less"; \ No newline at end of file diff --git a/app/resources/less/openlayers/controls.less b/app/resources/less/openlayers/controls.less new file mode 100644 index 0000000..97f278e --- /dev/null +++ b/app/resources/less/openlayers/controls.less @@ -0,0 +1,71 @@ +.mg-ol-control-zoom { + bottom: 3rem; + left: 1rem; + + >button { + height: 3rem; + width: 3rem; + font-size: 2.5rem; + } +} + +.control-geolocation { + bottom: 10rem; + left: 1rem; + + >button { + height: 3rem; + width: 3rem; + font-size: 3rem; + } + + &.locked { + >button { + color: rgb(255, 127, 0); + } + } + + &.on { + >button { + color: rgba(255, 127, 0, 0.5); + } + } +} + +.ol-attribution { + bottom: 6rem !important; + right: 1rem; + + >button { + height: 2rem; + width: 2rem; + font-size: 2rem; + } + + >ul { + height: 2rem; + line-height: 2rem !important; + background-color: white; + font-size: 1.25rem !important; + } +} + +.ol-control { + + &.nav-opener { + right: 1rem; + top: 2rem; + + >button { + height: 4rem; + width: 4rem; + font-size: 3rem; + } + } +} + +.ol-scale-line { + left: unset; + right: 1rem; + bottom: 3rem; +} \ No newline at end of file diff --git a/app/resources/views/map.blade.php b/app/resources/views/map.blade.php index f237b65..f1a7287 100644 --- a/app/resources/views/map.blade.php +++ b/app/resources/views/map.blade.php @@ -9,40 +9,41 @@ Maps - MetaGer </title> @if (isset($css)) - @foreach ($css as $el) - <link href="{{ $el }}" rel="stylesheet" type="text/css" /> - @endforeach + @foreach ($css as $el) + <link href="{{ $el }}" rel="stylesheet" type="text/css" /> + @endforeach @endif <meta name="tileserverhost" content="{{ config('maps.tileserver.host') }}"> @if (isset($bbox)) - <meta name="start-bbox" content="{{ $bbox }}"> + <meta name="start-bbox" content="{{ $bbox }}"> @endif @if (isset($module)) - <meta name="module" content="{{ $module }}"> + <meta name="module" content="{{ $module }}"> @endif @if (isset($query)) - <meta name="start-query" content="{{ $query }}"> + <meta name="start-query" content="{{ $query }}"> @endif @if (isset($viewbox)) - <meta name="start-viewbox" content="{{ $viewbox }}"> + <meta name="start-viewbox" content="{{ $viewbox }}"> @endif @if (isset($reverse_lon) && isset($reverse_lat) && isset($reverse_zoom)) - <meta name="start-reverselon" content="{{ $reverse_lon }}"> - <meta name="start-reverselat" content="{{ $reverse_lat }}"> - <meta name="start-reversezoom" content="{{ $reverse_zoom }}"> + <meta name="start-reverselon" content="{{ $reverse_lon }}"> + <meta name="start-reverselat" content="{{ $reverse_lat }}"> + <meta name="start-reversezoom" content="{{ $reverse_zoom }}"> @endif @if (isset($waypoints) && isset($vehicle)) - <meta name="start-vehicle" content="{{ $vehicle }}"> - <meta name="start-waypoints" content="{{ $waypoints }}"> + <meta name="start-vehicle" content="{{ $vehicle }}"> + <meta name="start-waypoints" content="{{ $waypoints }}"> @endif @if (Request::filled('bounded') && in_array(Request::input('bounded'), ['enabled', 'disabled'])) - <meta name="start-bounded" content="{{ Request::input('bounded') }}"> + <meta name="start-bounded" content="{{ Request::input('bounded') }}"> @endif @if (isset($navigation_active) && $navigation_active === true) - <meta name="navigation_active" content="true"> + <meta name="navigation_active" content="true"> @endif + <link rel="stylesheet" href="{{ mix('/css/map.css') }}" rel="stylesheet" type="text/css"> <link rel="stylesheet" href="{{ mix('/css/result.css') }}" rel="stylesheet" type="text/css"> <link rel="stylesheet" href="{{ mix('/css/nav-arrows.css') }}" rel="stylesheet" type="text/css"> <link rel="stylesheet" href="{{ mix('/css/navbar.css') }}" rel="stylesheet" type="text/css"> @@ -52,13 +53,14 @@ <link rel="stylesheet" href="{{ mix('/css/routefinder.css') }}" rel="stylesheet" type="text/css"> <link rel="stylesheet" href="{{ mix('/css/navigation.css') }}" rel="stylesheet" type="text/css"> @if (!\App::environment('production')) - <link rel="stylesheet" href="{{ mix('/css/fakegps.css') }}" rel="stylesheet" type="text/css"> + <link rel="stylesheet" href="{{ mix('/css/fakegps.css') }}" rel="stylesheet" type="text/css"> @endif </head> <body> <div id="page"> - <div class="close-container"><button class="close" aria-label="Unterseite schließen" title="Unterseite schließen">âŒ</button></div> + <div class="close-container"><button class="close" aria-label="Unterseite schließen" + title="Unterseite schließen">âŒ</button></div> <iframe src="" frameborder="0"></iframe> </div> <main> @@ -68,7 +70,7 @@ @include('addons/route') @include('addons/offline') @if (!\App::environment('production')) - @include('addons/fakegps') + @include('addons/fakegps') @endif <div class="map" id="map"> @@ -88,7 +90,7 @@ <li><a href="https://metager.de/datenschutz" target="_blank">Datenschutz</a></li> <li><a href="https://metager.de/impressum" target="_blank">Impressum</a></li> @if (!\App::environment('production')) - <li><a href="#" id="nav-fakegps">Fake GPS</a></li> + <li><a href="#" id="nav-fakegps">Fake GPS</a></li> @endif </ul> <div class="updates"> @@ -97,8 +99,7 @@ <div>Zeitzone: <span class="data-date-timezone"></span></div> <div>Karte: <span class="data-date-tiles"><img src="/img/ajax-loader.gif" alt="Loading data..."></span> </div> - <div>Suche: <span class="data-date-search"><img src="/img/ajax-loader.gif" - alt="Loading data..."></span> + <div>Suche: <span class="data-date-search"><img src="/img/ajax-loader.gif" alt="Loading data..."></span> </div> <div>Routen: <span class="data-date-routing"><img src="/img/ajax-loader.gif" alt="Loading data..."></span></div> @@ -111,4 +112,4 @@ <script src="{{ mix('js/map.js') }}" type="text/javascript" defer></script> </body> -</html> +</html> \ No newline at end of file diff --git a/app/webpack.mix.js b/app/webpack.mix.js index 03d0d9e..c041d9f 100644 --- a/app/webpack.mix.js +++ b/app/webpack.mix.js @@ -13,10 +13,6 @@ const mix = require("laravel-mix"); var mapJsFiles = [ "resources/js/app.js", - "resources/js/map/MetaGerMap.js", - "resources/js/map/Maplibre.js", - "resources/js/map/Openlayers.js", - "resources/js/map/MetaGerMapModule.js", "resources/js/AndroidConnector.js", "resources/js/NavbarControl.js", "resources/js/NominatimParser.js", @@ -53,6 +49,7 @@ mix mix.js(mapJsFiles, "public/js/map.js"); mix.scripts(["resources/js/turf.min.js"], "public/js/turf.min.js"); +mix.less("resources/less/map.less", "public/css/map.css"); mix.less("resources/less/navbar.less", "public/css/navbar.css"); mix.less("resources/less/result.less", "public/css/result.css"); mix.less("resources/less/nav-arrows.less", "public/css/nav-arrows.css"); -- GitLab