How to NOT change camera center upon GeolocateControl trigger? - mapbox-gl-js

I have a Mapbox web app map that I want to add the user's location to, but NOT have the map automatically recenter itself on the user's location. The example code here https://docs.mapbox.com/mapbox-gl-js/example/locate-user/ works great, I just don't want the map to recenter on the user.
This is specifically the code I'm using:
// GEO LOCATE USER!
const geolocate = new mapboxgl.GeolocateControl({
positionOptions: {
enableHighAccuracy: false
},
trackUserLocation: false
});
map.addControl(geolocate,"bottom-left");
geolocate.trigger();
Is there a way to have the geolocate.trigger() be a passive experience and not recenter the map, just add the user's location to it?

Mapbox-GL doesn't expose an official API to disable auto-tracking of a user's location with the camera, but you can monkey-patch it to accomplish what you want:
const locate = new mapboxgl.GeolocateControl({
positionOptions: { enableHighAccuracy: true },
trackUserLocation: true
})
// hacky workaround for the fact that mapbox doesn't let you disable camera auto-tracking
locate._updateCamera = () => {}
this.map.addControl(locate)
This works by replacing the internal _updateCamera method with a noop:
- https://github.com/mapbox/mapbox-gl-js/blob/2693518e8d042b3120c33f08433abbc3b114d25c/src/ui/control/geolocate_control.js#L187

Related

Mapbox GL JS not showing user heading, always points north

I have a Mapbox-GL-JS script that is working fine. However, the arrow next to the blue user location dot always points north. I thought the showUserHeading option is supposed to point in the direction (bearing) the user is moving. Anyone have a fix for this?
var geolocate = new mapboxgl.GeolocateControl({
positionOptions: {
enableHighAccuracy: true
},
trackUserLocation: true,
showUserHeading: true,
showUserLocation: true,
showAccuracyCircle: true
});

Mapbox GL JS: Control max zoom with geolocation control?

I am using Mapbox GL JS v0.32.1 and I have a geolocation control on my map.
I would like to make it so that the maximum zoom when the user geolocates is 8, so that the map zooms to the user's approximate location, not street location.
According to the documentation there should be a geolocate event available, but this isn't working for me:
var geoLocate = map.addControl(new mapboxgl.GeolocateControl());
geoLocate.on('geolocate', function(e) {
console.log('geolocated');
map.setZoom(8);
})
Geolocating (in Chrome at least) still zooms to the maximum zoom level available, and I don't see a console log message when it happens.
Map#addControl returns Map. The geolocate event is fired on GeolocateControl. The following should work:
var geoLocate = new mapboxgl.GeolocateControl();
map.addControl(geoLocate);
geoLocate.on('geolocate', function(e) {
console.log('geolocated');
map.setZoom(8);
});
Try this way. smooth zoom to your location
var geoLocate = new mapboxgl.GeolocateControl();
map.addControl(geoLocate);
geoLocate.on('geolocate', function(e) {
map.flyTo({
center:[e.coords.longitude, e.coords.latitude],
zoom:16 //set zoom
});
});

Mapbox GL JS Bearing

Is it possible in Mapbox GL JS to get the users bearing?
I would like to show the direction in which the user is facing, to assist them in navigating to nearby POI.
I understand that it is possible to set the bearing of the map and also get the current bearing of it, but i need the actual real life bearing of the user.
Kind of the same thing as on Google Maps:
The service is intended to run as an Ionic app on iOS and Android, and the assistance in bearing is a key feature in helping them locate nearby POI on a well populated map.
You can get the user's bearing (if their device has such a sensor) by obtaining a Coordinates object from Gelocation#getCurrentPosition() and reading Coordinates#heading.
Mapbox GL JS has no built-in user interface for displaying a user's heading. Building your own user interface is easy. See this example which uses the symbol-rotation property.
So, after some time spend on this, i thought I'd show how i ended up doing this, in case someone else needs it or have a better solution.
It seems cordova has a built in "heading" property in the position object.
https://github.com/apache/cordova-plugin-geolocation
var heading = $rootScope.position.heading;
First, i make sure that the marker is always pointing in the heading direction, even when the user turns the map, by subtracting the mapBearing(degrees the map has turned from North), from the user heading.
map.on('rotate', function(){
map.setLayoutProperty('drone', 'icon-rotate', heading - map.getBearing())
});
I create an icon, at the users position, add the source and add the layer with the source.
map.on('load', function () {
var point = {"type": "Point", "coordinates": [$rootScope.position.long, $rootScope.position.lat]};
map.addSource('drone', {type: 'geojson', data: point });
map.addLayer({
"id": "drone",
"type": "symbol",
"source": "drone"
}
});
Next i check that heading is actually available, since it only appears to return a value, when the user is moving(only tested on Android so far), and if it is, update the heading of the point.
if($rootScope.position.heading){
var heading = $rootScope.position.heading;
map.setLayoutProperty('drone', 'icon-rotate', $rootScope.position.heading);
};
Finally i update the position of the point, in a "$watch" position.
map.getSource('drone').setData(point);
This way, i can watch the users heading, and the point keeps on track, even when the user rotates the map.
For the users coming here after 2020 (what an year lol), mapbox gl js now supports geolocation which not only provides user's heading but also a bunch of other helpful data:
const geolocate = map.addControl(
new mapboxgl.GeolocateControl({
positionOptions: {
enableHighAccuracy: true
},
trackUserLocation: true
})
)
then listen for geolocate event:
geolocate.on('geolocate', (e) => {
console.log(e);
});
this will give you following object:
{
coords: {
accuracy: number;
altitude: number;
altitudeAccuracy: number;
heading: number;
latitude: number;
longitude: number;
speed: number;
};
timestamp: number;
heading will give you direction of the user. As the geolocate control keeps triggering automatically so can get the user's direction as well as speed and altitude etc in real time and use that to display data driven symbols on map.

Mapbox GL directions plugin hiding search origin destination box

I am using Mapbox GL directions plugin inside my app where I set the origin on map load and set driving destination upon user click on any location on the map. I am now trying to remove the top left search origin / destination box yet after extensive research can't figure out how to do so, can someone please help by telling me how to do so? Thanks.
Code I am using in my app below:
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v8',
center: [userCoordinates.coords.longitude, userCoordinates.coords.latitude],
zoom: 15
});
var directions = new mapboxgl.Directions({
unit: 'metric',
profile: 'driving'
});
map.addControl(directions);
directions.setOrigin([userCoordinates.coords.longitude, userCoordinates.coords.latitude]);
map.on('click', function(e) {
var features = map.queryRenderedFeatures(e.point, { layers: ['gsLayer'] });
if (!features.length) {
return;
}
var feature = features[0];
directions.setDestination([feature.geometry.coordinates[0], feature.geometry.coordinates[1]]);
});
I couldn’t figure this out either since there is no documentation, but finally I read through the mapbox-gl-directions.js file and I think I found out how to do it.
In your example, you should embed the controls like this in order to remove the origin / destination box:
var directions = new mapboxgl.Directions({
unit: 'metric',
profile:'driving',
container:'directions', // Specify an element thats not the map container.
// UI controls
controls: {
inputs: false,
instructions: true
}
});
map.addControl(directions);
I'll assume you are using Mapbox GL Javascript, and looking at this example it appears map.addControl(new mapboxgl.Directions()); is what is adding the controller. Within your code you gave you also have this map.addControl(directions);. Try removing it and see what happens.
Hope this helps!

Leaflet: map.locate set maxZoom dynamically

It is easy to track a users position and show a position marker with Leaflet
_map.locate({
watch: true,
setView: true,
maxZoom: 13,
enableHighAccuracy: true
})
and some code in the locationfound callback.
However, the user might wish to zoom to a differed level, but when the position maker gets updated the map always zooms back to the value set in the locate maxZoom option.
Is there a way to change the maxZomm value dynamically depending on the zoom level the user has chosen?
Well, after digging a bit in the source it is just as easy as this:
Listen to the zoomend event
_map.on('zoomend', _changeLocateMaxZoom);
and then update the locateOptions maxZoom
function _changeLocateMaxZoom(e) {
if (_map._locateOptions) {
_map._locateOptions.maxZoom = _map.getZoom();
}
}
Leaflet is a well designed library.