Disable button while waiting for google maps directionService - javascript

I am trying to disable a html button while waiting for google maps service call, in my case, when using google maps service to trace route with multiple waypoints and slow 3G throttling, the button should be disabled until tracing the new route .
calculateRoad(departure: any, arrival: any) {
const request = {
origin: departure,
destination: arrival,
waypoints: waypts,
optimizeWaypoints: false,
travelMode: this.getTravelModeFromVehicleType(vehicleType),
};
this.googleMapComponent.directionsService.route(request, (response, status) => {
if (status === google.maps.DirectionsStatus.OK) {
}
else if (vehicleType == Model.VehicleType.Bicycle && status == google.maps.DirectionsStatus.ZERO_RESULTS) {
}
else {
}
this.googleMapComponent.directionsDisplay.setDirections(response);
});
}

When making request you can set some default value/state/behaviorsubject or something to be true like:
let loading = true;
then in the request where the new route is set you just need to set loading to be false:
loading = false;
In html file:
(if loading is true disable button)
<button [disabled]='loading'>...</button>

Related

position error in localization in react.js

I have the following code that takes the user's location from a google api, the detail I have is that the accuracy is too high, for example accuracy: 2600.670416166183, I don't know if someone knows how to solve this error, it would be very useful
const useGeoLocation = () => {
const [location, setLocation] = useState({
loaded: true,
coordinates: {
lat: "",
lng: "",
},
aceptacion: null,
});
const onSuccess = (location) => {
console.log(location);
setLocation({
loaded: true,
coordinates: {
lat: resultado.location.lat,
lng: resultado.location.lng,
},
aceptacion:1
});
};
useEffect(() => {
const url = `https://www.googleapis.com/geolocation/v1/geolocate?key=......`;
const http = new XMLHttpRequest();
http.open("POST", url);
http.onreadystatechange = function(){
if(this.readyState == 4 && this.status == 200){
let resultado = JSON.parse(this.responseText);
let latitude = resultado.location.lat;
let longitude = resultado.location.lng;
setLocation({
loaded: true,
coordinates: {
lat: resultado.location.lat,
lng: resultado.location.lng,
},
aceptacion:1
});
console.log(resultado);
return resultado
}
}
http.send();
}, []);
return location;
}; export default useGeoLocation;
I think you are using the wrong API for your needs.
Google Geolocation API is used to get location from Wifi/Bluetooth/Cell Tower/IP informations. In your example you don't put any additional information in the body of your request, so google will only give geolocation based on the user's IP, which doesn't have a good accuracy.
If you want a better accuracy using this API, you have to provides Wifi or Bluetooth spots near the user (see documentation here), but I don't think that's what you want, so I think the best solution is to use navigator.geolocation.getCurrentPosition native function from all browsers, it will get location directly from the device (GPS/Wifi/Bluetooth) like there :
https://developers.google.com/maps/documentation/geolocation/overview
You can find examples here :
How do I get user's location via navigator.geolocation before my fetch executes in componentDidMount() in react.js?
How to get location information in react?

Clear directions on Google Map with VueJS

I have the following code in my app:
createCargoRoute: function(cargo_id) {
var directionsService = new google.maps.DirectionsService();
var directionsDisplay = new google.maps.DirectionsRenderer();
var storehouse = new google.maps.LatLng(53.243757, 50.269379);
var cargo_orders = this.orders.filter(order => this.cargos[cargo_id]['orders_ids'].includes(order.id));
var cargo_waypoints = cargo_orders.map(cargo_order => cargo_order['waypoint']);
directionsDisplay.setMap(this.$refs.olkonmap.$mapObject);
directionsService.route({
origin: storehouse,
destination: storehouse,
travelMode: 'DRIVING',
waypoints: cargo_waypoints,
optimizeWaypoints: true
}, function(result, status) {
if(status == 'OK') {
directionsDisplay.setDirections(result);
}
});
},
It works, but when I call it second time to draw another route, the first route doesn't removes from map. I read that I need to call directionsDisplay.setDirections(null) to clear directions and it works, for example, if I add setTimeout(function() { directionsDisplay.setDirections(null); }, 2000);
to createCargoRoute function.
But if I add directionsDisplay.setDirections(null); before any actions in createCargoRoute, it has no effect at second call. I think, it may be due to new DirectionsRenderer object which instantiates every time I call the function. Any advice would be appreciated. Thank you!
This is not good idea to create new DirectionsService and DirectionsRenderer on each call. Move them to mounted() and keep instances in component options (instead of putting them to data). Maybe it help:
export default {
// will be accessible via this.$options because no reactive data is needed
directionsService: null,
directionsDisplay: null,
mounted() {
this.$options.directionsService = new google.maps.DirectionsService();
this.$options.directionsDisplay = new google.maps.DirectionsRenderer();
this.$options.directionsDisplay.setMap(this.$refs.olkonmap.$mapObject);
},
methods: {
createCargoRoute: function(cargo_id) {
// clear existing directions
this.$options.directionsDisplay.set('directions', null);
var storehouse = new google.maps.LatLng(53.243757, 50.269379);
var cargo_orders = this.orders.filter(order => this.cargos[cargo_id]['orders_ids'].includes(order.id));
var cargo_waypoints = cargo_orders.map(cargo_order => cargo_order['waypoint']);
this.$options.directionsService.route({
origin: storehouse,
destination: storehouse,
travelMode: 'DRIVING',
waypoints: cargo_waypoints,
optimizeWaypoints: true
}, (result, status) => {
if(status == 'OK') {
this.$options.directionsDisplay.setDirections(result);
}
});
},
}
}

Removing directions overlay using angular-google-maps and angular2

Im using an api to populate a map with several markers, my desired functionality is for a user to click a button associated with a marker and it would plot directions from their current location. On the first instance it works perfectly but the current directions plotted just remain when trying to change the coordinates
Im using angular2-google-maps to plot the markers but I had to find a custom directive for directions. I think the problem is that I need to destroy the instance of the directions but using ngIf didnt help. I also tried resetting the instance of the direction in my directive using directionsDisplay.set('directions', null); but that didnt work either
/* directions.directive.ts */
import {GoogleMapsAPIWrapper} from '#agm/core/services/google-maps-api-wrapper';
import { Directive, Input} from '#angular/core';
declare var google: any;
#Directive({
selector: '<agm-map-directions [origin]="origin" [destination]="destination" #test></agm-map-directions>'
})
export class DirectionsMapDirective {
#Input() origin;
#Input() destination;
constructor (private gmapsApi: GoogleMapsAPIWrapper) {}
ngOnInit(){
this.gmapsApi.getNativeMap().then(map => {
var directionsService = new google.maps.DirectionsService;
var directionsDisplay = new google.maps.DirectionsRenderer;
console.log("test");
directionsDisplay.setMap(map);
directionsService.route({
origin: {lat: this.origin.latitude, lng: this.origin.longitude},
destination: {lat: this.destination.latitude, lng: this.destination.longitude},
waypoints: [],
optimizeWaypoints: true,
travelMode: 'DRIVING'
}, function(response, status) {
if (status === 'OK') {
directionsDisplay.setDirections(response);
} else {
window.alert('Directions request failed due to ' + status);
}
});
});
}
}
Here is the html associated with it
<agm-map [zoom]="13" [latitude]="currentLocation.result.latitude" [longitude]="currentLocation.result.longitude">
<agm-marker [latitude]="currentLocation.result.latitude" [longitude]="currentLocation.result.latitude"></agm-marker>
<agm-marker *ngFor="let device of location.ChargeDevice; let i = index"
ngShow="device.SubscriptionRequiredFlag"
[latitude]="convertStringToNumber(device.ChargeDeviceLocation.Latitude)"
[longitude]="convertStringToNumber(device.ChargeDeviceLocation.Longitude)"
(markerClick)="clickedMarker(device)">
</agm-marker>
<div *ngIf="showDirections" >
<agm-map-directions [origin]="origin" [destination]="destination" #test></agm-map-directions>
</div>
</agm-map>
I had the same problem as you.
I solved it by creating a global object that holds the instantiation of directionsService and directionsDisplay, to be able to pass those as reference later. ( See javascript pass by reference )
public directions: any = {
directionsService: null,
directionsDisplay: null
}
Then, I created a function that initialize the map once and I called it within ngOnInit() function:
constructor(private _gmapsApi: GoogleMapsAPIWrapper) { }
ngOnInit() {
this.initalizeMap(this.directions);
}
initalizeMap(directions): void {
this._gmapsApi.getNativeMap().then(map => {
directions.directionsService = new google.maps.DirectionsService;
directions.directionsDisplay = new google.maps.DirectionsRenderer;
directions.directionsDisplay.setMap(map);
directions.directionsDisplay.addListener('directions_changed', function() {
this.displayRoute(this.origin, this.destination, directions.directionsService, directions.directionsDisplay);
});
this.displayRoute(this.origin, this.destination, directions.directionsService, directions.directionsDisplay);
})
}
I added a listener to directionsDisplay to displayRoute whenever a change is made in the directions. The function displayRoute take as parameters origin and destination passed through #Input and references to directionsService and directionsDisplay whose instances I saved in directions object. The waypoints I took are also through #Input.
displayRoute(origin, destination, service, display): void {
var myWaypoints = [];
for (var i = 0; i < this.waypoints.length; i++) {
console.log(this.waypoints[i].markerID);
console.log(this.waypoints[i].location);
}
for (var i = 0; i < this.waypoints.length; i++) {
myWaypoints.push({
location: new google.maps.LatLng(this.waypoints[i].location),
stopover: true
})
}
service.route({
origin: origin,
destination: destination,
waypoints: myWaypoints,
travelMode: 'WALKING',
avoidTolls: true
}, function(response, status) {
if (status === 'OK') {
console.log("Route OK.");
display.setDirections(response);
} else {
alert('Could not display directions due to: ' + status);
}
});
}
The last function and the most important is calculateRoute, which I call from the component I injected the service ( Map Component in my case ) whenever I want it to recalculate the route.
calculateRoute(): void {
this._gmapsApi.getNativeMap().then(map => {
this.displayRoute(this.origin, this.destination, this.directions.directionsService, this.directions.directionsDisplay);
});
}
Hope it helps!

Dotted route when travel mode for driving is not supported

I am trying to make the route for my map in ionic, and I can't seem to find a way to show the route as dotted when the travel mode for driving is not available - like on the google maps.
This is how my maps route looks like:
without the dotted route ->
This is how google maps route looks like:
with the dotted route ->
This is how the code for the route looks like for now:
function route(travel_mode, directionsService, directionsDisplay) {
console.log($scope.transfer.origin.place_id, $scope.transfer.destination.place_id);
if (!$scope.transfer.origin.place_id || !$scope.transfer.destination.place_id) {
return;
}
else if (ok == 0) {
ok = 1;
directionsService.route({
origin: {
'placeId': $scope.transfer.origin.place_id
}
, destination: {
'placeId': $scope.transfer.destination.place_id
}
, travelMode: travel_mode
}, function (response, status) {
if (status === 'OK') {
directionsDisplay.setDirections(response);
var origin1 = $scope.transfer.origin.place_title;
var destinationA = $scope.transfer.destination.place_title;
console.dir(origin1);
var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix({
origins: [origin1]
, destinations: [destinationA]
, travelMode: 'DRIVING'
, unitSystem: google.maps.UnitSystem.METRIC
}, callback);
function callback(response, status) {
console.dir(response);
if (status == 'OK') {
origins = response.originAddresses[0];
destinations = response.destinationAddresses[0];
results = response.rows[0].elements[0];
distance = results.distance.text;
duration = results.duration.text;
DTransfer.setData('distance', distance);
DTransfer.setData('duration', duration);
}
}
}
else {
window.alert('Directions request failed due to ' + status);
}
});
}
}
}
If there is any fix, can anybody help?

React.js, where to put google maps api queries?

I'm building a google maps app with React.js.
My instinct is to create separate file with an ES6 class to handle search queries - within the class there will be a function that returns the search result. I intend to call that function from within a React Component.
See the component below for reference.
Should I move the code inside the findRoutes() and drawBoxes() methods to separate files? This is my first react app - want to learn how to best organize the code. Any tips are hugely appreciated.
var MapControl = React.createClass({
getInitialState: function(){
return {
originId: '',
destinationId: '',
radius: 1,
search: '',
map: {},
travelMode: google.maps.TravelMode.DRIVING
}
},
handleFormSubmit: function(input){
// Form Input
// Call findRoutes() once setState is complete.
this.setState({
originId: input.originId,
destinationId: input.destinationId,
radius: input.radius,
search: input.search
}, this.findRoutes);
},
handleMapRender: function(map){
// Intialized Google Map
this.setState({map: map});
directionsService = new google.maps.DirectionsService();
directionsDisplay = new google.maps.DirectionsRenderer();
routeBoxer = new RouteBoxer();
directionsDisplay.setMap(map);
placesService = new google.maps.places.PlacesService(map);
},
findRoutes: function(){
var me = this;
if (!this.state.originId || !this.state.destinationId) {
alert("findRoutes!");
return;
}
directionsService.route({
origin: {'placeId': this.state.originId},
destination: {'placeId': this.state.destinationId},
travelMode: this.state.travelMode
}, _.bind(function(response, status){
if (status === google.maps.DirectionsStatus.OK) {
// me.response = response;
directionsDisplay.setDirections(response);
var path = response.routes[0].overview_path;
this.setState({
routes: response,
boxes: routeBoxer.box(path, this.state.radius)
},this.drawBoxes);
} else {
window.alert('Directions config failed due to ' + status);
}
}, this));
},
drawBoxes: function(){
var boxpolys = new Array(this.state.boxes.length);
for (var i = 0; i < this.state.boxes.length; i++) {
boxpolys[i] = new google.maps.Rectangle({
bounds: this.state.boxes[i],
fillOpacity: 0,
strokeOpacity: 1.0,
strokeColor: '#000000',
strokeWeight: 1,
map: this.state.map
});
}
},
render: function() {
return (
<div className="MapControl">
<h1>Search</h1>
<MapForm
onFormSubmit={this.handleFormSubmit}
map={this.state.map}/>
<GMap
setMapState={this.handleMapRender}
originId= {this.state.originId}
destinationId= {this.state.destinationId}
radius= {this.state.radius}
search= {this.state.search}/>
</div>
);
}
});
Your instinct is correct, in general it's good practice to keep your view code as minimal as possible, and to move anything that is not explicitly related to rendering your view into another class.
React.js itself is not opinionated as to how you handle the rest of your application needs but a few libraries have emerged as the leading solutions for handling events, routing, services, data, etc.
You should review the Flux pattern for an overview of how you might manage the rest of your applications needs for React apps.
https://facebook.github.io/flux/docs/overview.html
I've moved on from Flux to using Redux recently
http://redux.js.org/ (which has emerged as the leading 'Fluxish' state management lib)
If you want to just get something up and running quickly and aren't trying to dive into all that just yet, I'd move the findRoutes method to an external service that you import in... drawBoxes seems fine to keep in here as it is directly related to rendering map elements in the view

Categories

Resources