From 41f86411308c0c5d96a39dc3c23bf51fdfef5b4a Mon Sep 17 00:00:00 2001 From: Paola De Bartolo Date: Thu, 14 Mar 2024 17:20:05 -0300 Subject: [PATCH] feat: add possibility to track location Close #117 --- .../vaadin/addons/googlemaps/GoogleMap.java | 55 ++++++++++++++ .../frontend/googlemaps/geolocation.js | 54 +++++++++---- .../addons/googlemaps/GooglemapsDemoView.java | 1 + .../addons/googlemaps/TrackLocationDemo.java | 76 +++++++++++++++++++ 4 files changed, 172 insertions(+), 14 deletions(-) create mode 100644 src/test/java/com/flowingcode/vaadin/addons/googlemaps/TrackLocationDemo.java diff --git a/src/main/java/com/flowingcode/vaadin/addons/googlemaps/GoogleMap.java b/src/main/java/com/flowingcode/vaadin/addons/googlemaps/GoogleMap.java index f25a91a..b42629d 100644 --- a/src/main/java/com/flowingcode/vaadin/addons/googlemaps/GoogleMap.java +++ b/src/main/java/com/flowingcode/vaadin/addons/googlemaps/GoogleMap.java @@ -609,6 +609,61 @@ public Registration addGeolocationErrorEventListener( ComponentEventListener listener) { return addListener(GeolocationErrorEvent.class, listener); } + + /** + * Activates tracking current location on map. + * + *

Uses geolocation#watchPosition + * method to track current position.

+ * + *

Geolocation requires that the user gives consent to location sharing when prompted by the + * browser.

+ */ + public void trackLocation() { + getElement().executeJs("return geolocation.trackLocation($0)", this).then(Integer.class, + trackLocationId -> { + ComponentUtil.fireEvent(this, + new LocationTrackingActivatedEvent(this, false, trackLocationId)); + }); + } + + /** Event that is fired when activating location tracking. */ + public class LocationTrackingActivatedEvent extends ComponentEvent { + + private Integer trackLocationId; + + public LocationTrackingActivatedEvent(GoogleMap source, boolean fromClient, + Integer trackLocationId) { + super(source, fromClient); + this.trackLocationId = trackLocationId; + } + + public Integer getTrackLocationId() { + return trackLocationId; + } + } + + /** + * Adds a LocationTrackingActivatedEvent listener. The listener is called when setting activating + * tracking location. + * + * @param listener a listener for a LocationTrackingActivatedEvent + * @return a handle for the listener + */ + public Registration addLocationTrackingActivatedEventListener( + ComponentEventListener listener) { + return addListener(LocationTrackingActivatedEvent.class, listener); + } + + /** + * Stops location tracking. + * + * @param trackLocationId the id of the current activated location tracking + */ + public void stopTrackLocation(Integer trackLocationId) { + getElement().executeJs("geolocation.clearTracking($0)", trackLocationId); + } /** * Returns a {@link CompletableFuture} containing the map current {@link LatLonBounds bounds}. diff --git a/src/main/resources/META-INF/resources/frontend/googlemaps/geolocation.js b/src/main/resources/META-INF/resources/frontend/googlemaps/geolocation.js index 7dde6fe..e8441ac 100644 --- a/src/main/resources/META-INF/resources/frontend/googlemaps/geolocation.js +++ b/src/main/resources/META-INF/resources/frontend/googlemaps/geolocation.js @@ -20,20 +20,46 @@ window.geolocation = { get: function(map) { - // if browser supports geolocation, return current location - if(navigator.geolocation) { + // if browser supports geolocation, return current location + if (navigator.geolocation) { - navigator.geolocation.getCurrentPosition( - position => { - map.$server.handleGeolocation(position.coords.latitude, position.coords.longitude); - }, - () => { - map.$server.handleGeolocationError(true); - }); - - } else { // browser doesn't support geolocation - map.$server.handleGeolocationError(false); - } - } + navigator.geolocation.getCurrentPosition( + position => { + map.$server.handleGeolocation(position.coords.latitude, position.coords.longitude); + }, + () => { + this._handleGeolocationError(true, map); + } + ); + } else { // browser doesn't support geolocation + this._handleGeolocationError(false, map); + } + }, + + trackLocation: function(map) { + let trackLocationId; + if (navigator.geolocation) { + + trackLocationId = navigator.geolocation.watchPosition( + position => { + map.$server.handleGeolocation(position.coords.latitude, position.coords.longitude); + }, + () => { + this._handleGeolocationError(true, map); + } + ); + } else { // browser doesn't support geolocation + this._handleGeolocationError(false, map); + } + return trackLocationId; + }, + + clearTracking: function(id) { + navigator.geolocation.clearWatch(id); + }, + + _handleGeolocationError(error, map){ + map.$server.handleGeolocationError(error); + } } diff --git a/src/test/java/com/flowingcode/vaadin/addons/googlemaps/GooglemapsDemoView.java b/src/test/java/com/flowingcode/vaadin/addons/googlemaps/GooglemapsDemoView.java index 9076078..2ceb945 100644 --- a/src/test/java/com/flowingcode/vaadin/addons/googlemaps/GooglemapsDemoView.java +++ b/src/test/java/com/flowingcode/vaadin/addons/googlemaps/GooglemapsDemoView.java @@ -46,6 +46,7 @@ public GooglemapsDemoView() { addDemo(ClusteringWithCustomRendererDemo.class); addDemo(PolylinesDemo.class); addDemo(CustomizedMarkerIconsDemo.class); + addDemo(TrackLocationDemo.class); setSizeFull(); } } diff --git a/src/test/java/com/flowingcode/vaadin/addons/googlemaps/TrackLocationDemo.java b/src/test/java/com/flowingcode/vaadin/addons/googlemaps/TrackLocationDemo.java new file mode 100644 index 0000000..31d9c0b --- /dev/null +++ b/src/test/java/com/flowingcode/vaadin/addons/googlemaps/TrackLocationDemo.java @@ -0,0 +1,76 @@ +/*- + * #%L + * Google Maps Addon + * %% + * Copyright (C) 2020 - 2024 Flowing Code + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +package com.flowingcode.vaadin.addons.googlemaps; + +import com.flowingcode.vaadin.addons.demo.DemoSource; +import com.flowingcode.vaadin.addons.googlemaps.GoogleMap.MapType; +import com.vaadin.flow.component.button.Button; +import com.vaadin.flow.component.notification.Notification; +import com.vaadin.flow.router.PageTitle; +import com.vaadin.flow.router.Route; + +@PageTitle("Track Location Demo") +@DemoSource +@Route(value = "googlemaps/tracklocation", layout = GooglemapsDemoView.class) +@SuppressWarnings("serial") +public class TrackLocationDemo extends AbstractGoogleMapsDemo { + + private Integer trackLocationId = null; + + @Override + protected void createGoogleMapsDemo(String apiKey) { + GoogleMap gmaps = new GoogleMap(apiKey, null, null); + gmaps.setMapType(MapType.ROADMAP); + gmaps.setSizeFull(); + gmaps.setZoom(15); + add(gmaps); + + // create button to activate location tracking + Button startLocationTrackingButton = + new Button("Start tracking my location", e -> gmaps.trackLocation()); + // create button to stop location tracking + Button stopLocationTrackingButton = + new Button("Stop tracking my location", e -> gmaps.stopTrackLocation(trackLocationId)); + add(startLocationTrackingButton, stopLocationTrackingButton); + + // create marker to track location + GoogleMapMarker locationMarker = new GoogleMapMarker(); + locationMarker.setCaption("You're here"); + locationMarker.setDraggable(false); + gmaps.addMarker(locationMarker); + + // add listener to obtain id when track location is activated + gmaps.addLocationTrackingActivatedEventListener(ev -> { + trackLocationId = ev.getTrackLocationId(); + }); + + // add listener to know when location was updated and update location marker position + gmaps.addCurrentLocationEventListener(e -> { + locationMarker.setPosition(e.getSource().getCenter()); + }); + + // add listener to capture geolocation error + gmaps.addGeolocationErrorEventListener(e -> { + if (!e.isBrowserHasGeolocationSupport()) + Notification.show("Your browser doesn't support geolocation."); + }); + } +}