Recenter Mapbox map using user coords - javascript

Been trying for 1.5 hours. Can someone please help me out? "your post appears to contain code that is not properly formatted as code" issue.
Please can someone help me format this code?
It works now in this post, but not when making a new one...
Now I cannot make a new post for a day... What the...
FIXED: It appears that the browser output had to be in code layout.
This was my original question:
TITLE: Working with geolocation API - scope question
Hi all
I am working with Mapbox and am trying to update the vars lngreal and latreal (from default Greenwhich coordinates). The function initializeMap() is called during setup, and the idea is that it updates it with user's longlat coordinates if possible. When I run the code below...
function initializeMap() {
mapboxgl.accessToken = 'HIDDEN FOR THIS POST';
var lngreal = 0.0098;
var latreal = 51.4934;
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(displayLocationInfo);
}
function displayLocationInfo(position) {
//Why does this not work to update the map zoom?
lngreal = position.coords.longitude;
latreal = position.coords.latitude;
console.log(lngreal);
console.log(latreal);
}
console.log(lngreal);
console.log(latreal);
// This adds the map to your page
var map = new mapboxgl.Map({
// container id specified in the HTML
container: 'map',
// style URL
style: 'mapbox://styles/mapbox/light-v10',
// initial position in [lon, lat] format
center: [lngreal, latreal],
// initial zoom
zoom: 14
});
// More code after this but not related
}
It shows the following in html inspector console:
play-mapboxscripts.js:21 0.0098
play-mapboxscripts.js:22 51.4934
play-mapboxscripts.js:17 4.9212796
play-mapboxscripts.js:18 52.333704999999995
Why does it first show the last console.log lines, instead of the console.log lines in the displayLocationInfo function? Isn't that function called in the navigator.geolocation function, which comes before that?
I cannot get the lngreal and latreal variables updated correctly to match the user's location. They will default back to 0.0098 and 51.4934, and the loaded map (var map) will show the default Greenwhich location. Does this have to do with variable scope of the displayLocationInfo function?

It shows the last two console logs first because displayLocationInfo is the callback to the async method getCurrentPosition and so has to wait until that process has resolved before it can log the new coords.
To recenter the map with the new coords you need to do something like this:
function displayLocationInfo(position) {
const { coords: { latitude, longitude } } = position;
// Get a new lat/lng object
// https://docs.mapbox.com/mapbox-gl-js/api/#lnglatlike
const center = new mapboxgl.LngLat(longitude, latitude);
// Center the map
// https://docs.mapbox.com/mapbox-gl-js/api/#map#setcenter
map.setCenter(center);
}

Thanks Andy and #Chris G. I wasn't aware of asynchronous functions and am happy to have read about them now. Very helpful.
I have a question about callbacks, which relates to this topic. How does a function know that something is a callback; something that needs to be executed once certain I/O has completed. How does it know that it shouldn't execute right away? Is it defined in a function in a (standardized) way?
As far as I know the 'callback' keyword that is often used in an argument is just common practise, but does not automatically let the function interpret the argument as something that should start once certain I/O has completed.
Taking the below example, I have three questions (taken from https://medium.com/codebuddies/getting-to-know-asynchronous-javascript-callbacks-promises-and-async-await-17e0673281ee):
const request = require(‘request’);
function handleResponse(error, response, body){
if(error){
// Handle error.
}
else {
// Successful, do something with the result.
}
}
request('https://www.somepage.com', handleResponse);
What does the structure of the 'require' function look like so that it knows that argument 2 (handleResponse in this case) should be executed once the request has completed? I guess this gets down to the same question that I asked above.
Can functions be asynchronous even without the async keyword in the function? If yes, how does the browser know it's an asynchronous function?
In my code, is it possible to have the browser/script wait with execution of remaining code until the navigator.geolocation.getCurrentPosition has finished executing and therefore updated the lngreal latreal coords?

Related

Here API clustering error: "addLayer is not defined"

I am try to use clastering in my aplication but I am get a error addLayer is not defined".
I have no Idea how to resolve this issue.
I just copy and paste this sample function from Here API samples api clusters
And I'm passing lat and lng, to the function but addLayer is undefined.
I have the map object, but the addLayer is undefined.
function startClustering(map, data) {
// First we need to create an array of DataPoint objects,
// for the ClusterProvider
var dataPoints = data.map(function(item) {
return new H.clustering.DataPoint(item.latitude, item.longitude);
});
// Create a clustering provider with custom options for clusterizing the input
var clusteredDataProvider = new H.clustering.Provider(dataPoints, {
clusteringOptions: {
// Maximum radius of the neighbourhood
eps: 32,
// minimum weight of points required to form a cluster
minWeight: 2
}
});
// Create a layer tha will consume objects from our clustering provider
var clusteringLayer = new H.map.layer.ObjectLayer(clusteredDataProvider);
// To make objects from clustering provder visible,
// we need to add our layer to the map
map.addLayer(clusteringLayer);
}
And I'm passing lat and lng, to the function but addLayer is undefined.
I have the map object, bust does not exist addLayer.
I'm embed the script
<script type="text/javascript" src="https://js.api.here.com/v3/3.0/mapsjs-clustering.js"></script>
on my index.
I don't know how to resolve this issue.
If someone knows how to resolve I'm glad to listen
EDIT: Additional code per comment request:
function addMarkerToCameraGroup(map, coordinate, html) { // add and remove markers
document.querySelector(".camera-box").addEventListener("click", function() {
if (document.getElementsByClassName("camera-marker-position")[0] === undefined) {
map.addObject(cameraMarker);
self.startClustering(map, coordinate);
} else {
map.removeAll();
}
});
}
You asked this question a second time as: "Try to create a cluster unsing a sample but addLayer got undefinied" which doesn't include some of the details in this question. Given the additional edit / context you made on this question however, it would seem you are adding an event listener in which map is probably out of scope or not yet defined for visibility inside the anonymous function.
document.querySelector(".camera-box").addEventListener("click", function() {
if (document.getElementsByClassName("camera-marker-position")[0] === undefined) {
map.addObject(cameraMarker);
self.startClustering(map, coordinate);
} else {
map.removeAll();
}
});
You could do a typing check to see if map has been defined when the click event occurs and/or confirm whether it is an H.map. Without seeing the full listing, it may also be the case that you have not made map a global variable but instead declared it somewhere else in the page initialization so is out of scope when the click event is fired.
You can check JavaScript callback scope for details on closures where you could provide the map to the event when declaring the function. For more general information: JavaScript HTML DOM EventListener

Altering external variable from Google Maps' StreetViewService.getPanorama({},callback) method

I am running into trouble with this piece of code since I'm not sure how to fix it. I already asked this in the chats but couldn't figure out myself after some answers.
I want to get Panorama from StreetViewService using the method from the Google Maps javascript API from a StreetViewService getPanorama() method.
The method receives a literal with the coordinates and a radius, and a callback function that receives 2 parameters: data and status.
in that callback you check wether the service returns some images for street view or not, in which case you do one thing or another.
It seems the callback is executed asynchronously or the getPanorama method, executing some kind of ajax behind the scenes.
I'm pasting the code below, but first I explain my intentions. I need to return from one method I made inside a literal that is inside a self made library wether the the request has valid images for that requested coordinates or not by setting a variable to true or false and then at the end returning that value. However, even if I set the variable to true inside that callback anonymous function, when the variable returns, it always has it's initial value without it not being changed.
Here the code. Not everything, just the essential code.
Then my intention is to used the boolean returned to know if I have to switch one button active for some kind of job or not or do some things or not depending of if it returned true or false, Change some style etc as well.
I'd appreciate if you could change my code in a way it could be done. I was told about a callback solution or wrapping it into a promise. However I don't know how to do it. I used promisses in jquery but not in vanilla javascript. I'd like to see how the callback solution could be made as well with this code.
//Library not show for shortenning the example.
streetView: { //This is inside a library
valid_request: false,
event_key: null,
panorama: null,
setStreetView: function(coords, element) {
libMapa.streetView.valid_request = false; // Initialize the value again.
let sv_service = new google.maps.StreetViewService();
var latlng = coords;
sv_service.getPanorama({ // This is a method from Google Map Javascript API.
location: latlng,
radius: 50
}, function(data, status) {
if (status === google.maps.StreetViewStatus.OK) {
if (!libMapa.streetView.panorama) {
libMapa.streetView.panorama = new google.maps.StreetViewPanorama(element);
libMapa.streetView.panorama.setEnableCloseButton(true);
}
libMapa.streetView.panorama.setPano(null);
libMapa.streetView.panorama.setPano(data.location.pano);
libMapa.streetView.panorama.setVisible(true);
libMapa.streetView.valid_request = true;
} else {
alert("No images for this place");
// Otherwise variable stays as FALSE.
}
});
return libMapa.streetView.valid_request;
}
}
/****************************************/
//OUTSIDE THE LIBRARY IN INDEX.HTML
var sv_valid = libMapa.streetView.setStreetView(coords, div_mapa);
//sv_valid still shows false even if it should return true.
if (sv_valid) {
// "pressed" is to control a button as if it was a switch by activatinc and deactivating it.
pressed = false; // It always ends up being false even when it should return true.
element.style.cursor = "default";
libMapa.mapa.unByKey(libMapa.streetView.event_key);
}
Use a callback to do some action or modify some variable after the AJAX call to getPanorama() (and by proxy, setStreetView()) is complete.
Modify setStreetView() to accept a callback parameter and pass it along to getPanorama().
streetView {
// streetView variables etc.
setStreetView: function(coords, element, callback) {
// get ready for the AJAX call etc.
sv_service.getPanorama({
// parameter object
}, function(data, status){
// The getPanorama() callback.
// Do stuff with the data/status here,
// then call the callback function that you passed in to setStreetView.
// You can send data along (e.g. the result of the AJAX call) to the callback.
callback(someResult);
});
}
}
// somewhere else, where you're calling streetView.setStreetView()
var someVar = "foo";
streetView.setStreetView(someCoords, someElement, function(eventualResult){
someVar = eventualResult;
});
Here's a small example: https://jsfiddle.net/_jered/pgftxgf3/
I also highly suggest you do some research on AJAX, asynchronous JavaScript, and callbacks.

JavaScript callback firing out of sequence

I thought I'd finally figured out JavaScript callbacks as I found a use for one, but it is firing out of sequence.
In a Google Maps application I have a function which checks if the map is zoomed to the maximum level before allowing the user to store the (new) location of a marker.
The check function is:
function checkForMaxAccuracy(nextOperation) {
// Check at full zoom and alert if not
maxZoomService.getMaxZoomAtLatLng( newLocationMarker.getPosition(), function(response) {
var levelToZoomTo;
if (response.status != google.maps.MaxZoomStatus.OK) {
alert("Please ensure you are at maximum zoom to ensure most accurate placement possible.");
// continue after this alert as Mao could be fully zoomed but zoom service not reporting correctly
} else {
//alert("The maximum zoom at this location is: " + response.zoom);
if (response.zoom > map.getZoom()) {
alert("You must be zoomed in to the maximum to ensure most accurate placement possible before saving.\n\n Click [ Zoom here ] in theInfo Window to zoom to the maximum.");
// return after this error as Mao is definitely not fully zoomed
return;
}
// Call the update function to do the saving to the database
nextOperation();
}
});
}
Where nextOperation is the callback function.
This is called by two different functions, the first, and simplest (because it's not fully written yet) works perfectly:
function saveNewLocation() {
checkForMaxAccuracy(function () {
alert("save new");
});
}
If not fully zoomed I get the warning message displayed by the check function. If the map IS fully zoomed I get the alert 'save new' message displayed which is a place holder for the code to do the database update.
However, the same check function is also called from a more complete function. This other function is called when the user is updating the location of an existing marker.
This second function actually sets the onclick property of an HTML span object - effectively enabling and disabling the save control depending on what is going on.
In this function I am setting the onclick as follows:
document.getElementById('savePosition'+locationId).onclick = (state)?function(){checkForMaxAccuracy(doUpdate(locationId,"position"));}:null;
In this case, when I click the corresponding span element the doUpdate() function gets fired before the checkForMaxAccuracy() function.
(Apologies for the use of ternary operator.. I know if makes things a little difficult to read, but I'm leaving as is in my code in case I've got the bracketing or syntax slightly wrong here and that's what's causing my problems.)
My guess is I'm getting something fundamentally wrong in my 'understanding' of callback functions.
Can anyone explain what I'm doing wrong?
-FM
checkForMaxAccuracy(
doUpdate(locationId,"position")
);
will pass the returned value of doUpdate as an argument of checkForMaxAccuracy. In other words, you're not passing the callback function itself but its return value.
What you could do is:
checkForMaxAccuracy(
function() {
doUpdate(locationId,"position")
}
);

Set data inside getCurrentPosition function

I'm doing next:
First thing - I'm checking if I already have loaded latitude and longitude data. If I do have, I'm saving that into array named "location".
Second thing - if I don't have any loaded data, I'm trying to get current position. After that, I'm trying to save latitude and longitude for current position.
And, at the end, I'm calling setMap(); function where I check location array and where I'm generating a map.
Problem:
Well, as I said it...inside "getCurrentPosition", I'm trying to set current position into "location" array, and after that I'm trying to take those values inside setMap(); function. Here's the problem, but only when i set "location" values inside "getCurrentPosition". If I set "location" values manually before (from "data" array), everything works fine.
Also, when I call a setMap() function inside "getCurrentPosition", everything works fine...but when I call it from outside, won't work.
Can someone explain me what's going on and what can I do?
Here's my code:
location = new Array();
if (data.lat) {
location['lat'] = data.lat;
location['lng'] = data.lng;
} else {
if (!navigator.geolocation) {
//
} else {
navigator.geolocation.getCurrentPosition(function(position) {
location['lat'] = position.coords.latitude;
location['lng'] = position.coords.longitude;
});
}
}
setMap();
Thank you.
You are setting a different variable inside of getCurrentPosition.
I would suggest researching variable scope.
Check out this question.
--edit--
I did not realize that the function you were using was a part of Javascript, I thought you had written/gotten it from somewhere.
Also, I stand corrected about the scope. Since you are using an array, the scope is fine, you should be able to set it inside the callback function just fine.
I ran your code and got some strange printouts when I did a console.log on location.
I took a guess, and it appears that location is a reserved word. I bet that if you change the name of location to something else, your code should work fine.
--edit--
I should have realized this sooner actually, since location is the same as window.location, which is the browser bar location!

Javascript - returning a variable is failing

I'm trying to do something that should be pretty simple - but it's doing my head in.
I can't seem to get a variable to return from a function
var where;
if (navigator.geolocation) {
where = navigator.geolocation.getCurrentPosition(function (position) {
// okay we have a placement - BUT only show it if the accuracy is lower than 500 mtrs
//if (position.coords.accuracy <= 500 ) {
// put their lat lng into google
var meLatLng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
var image = "images/map_blue.png";
var myMarker = new google.maps.Marker({
position: meLatLng,
map: map,
title: "Your location, as provided by your browser",
icon: image,
zIndex: 50
});
//} // end 500 mtrs test
return meLatLng;
});
alert("A: "+where);
}
I have a global variable called where, I'm trying to fill it with LatLng information received from the browser using navigator.geolocation - it plots the user on the map - but alert(where) always returns undefined
What am I doing wrong?
Short answer, nothing,
Bit longer answer, well... you see, the problem is that it would appear that your anonymous function returns its value to the getCurrentPosition function, which it seems doesnt return anything at all.
In order to use your returned value you should instead use a callBack or handle the data where it is...
Simply try replacing return meLatLng with customCallBack(meLatLng) and then defined customCallBack somewhere along the line.
Or, since you have already defined where in the global scope you could try and replace return meLatLng with where = meLatLng and then remove where = from where = navigatior.geoloc....
If what I suspect is right, the last method wont work, since I believe getCurrentPosition is asynchronous, meaning that you leave the standard flow of the application as soon as you call it. Which is why you supply a function to it in the first place.

Categories

Resources