GPS accuracy is too high and geolocate point (blue dot) is jumping around in IOS-Safari after one of the updates in IOS 14 version? - mapbox

I have a web application that is built with mapbox-gl-js. The gps accuracy is jumping between 5m to 65m sometimes as high as 620m in IOS-Safari. Sometimes it stays at 65m for a long time. I also hear a lot of complaints from users that geolocate point (blue dot) is jumping around. These issues didn't exist 4-5 months ago. They cannot be reproduced in Android-Chrome. I built a POC app to get the bottom of these issues and having the same issues in this app https://laughing-sinoussi-270dac.netlify.app/. Any recommendation is appreciated!
App.js
// TO MAKE THE MAP APPEAR YOU MUST
// ADD YOUR ACCESS TOKEN FROM
// https://account.mapbox.com
mapboxgl.accessToken =
"ACCESS_TOKEN";
var map = new mapboxgl.Map({
container: "map", // container id
style: "mapbox://styles/mapbox/streets-v11",
center: [-96, 37.8], // starting position
zoom: 9 // starting zoom
});
let geolocate = new mapboxgl.GeolocateControl({
positionOptions: {
enableHighAccuracy: true
},
trackUserLocation: true,
fitBoundsOptions: {
maxZoom: 20
}
});
map.addControl(geolocate);
geolocate.on("geolocate", e => {
document.getElementById("info").innerHTML =
// e.point is the x, y coordinates of the mousemove event relative
// to the top-left corner of the map
JSON.stringify("accuracy: " + e.coords.accuracy + " m") +
"<br />" +
JSON.stringify("latitude: " + e.coords.latitude) +
" " +
JSON.stringify("longitute: " + e.coords.longitude);
// + '<br />' +
// JSON.stringify("longitude:"e.coords.longitude);
console.log(e);
});

Related

Leaflet - only one tile is loaded [duplicate]

I have a problem with Leaflet that actually holds up my whole work. For some reasons I can not explain, the UI of Leaflet is correctly loaded in my Intel XDK app, but there is only one map tile loaded - the same code works in another test app! Now, that I tried everything I could do, I hope that someone here can solve my problem.
For better understanding, here is the code in my leaflet.js (it isn't the leaflet.js, because I'm using the leaflet-src.js as script) and a screenshot of the map window of the app.
function initLeaflet() {
document.getElementById("map").setAttribute("style", "height:" + window.innerHeight + "px; width:" + window.innerWidth + "px;");
var map = L.map('map');
L.tileLayer('https://{s}.tiles.mapbox.com/v3/{id}/{z}/{x}/{y}.png', {
maxZoom: 18,
attribution: 'Map data © OpenStreetMap contributors, ' +
'CC-BY-SA, ' +
'Imagery © Mapbox',
id: 'examples.map-i875mjb7'
}).addTo(map);
map.on('locationfound', onLocationFound);
map.on('locationerror', onLocationError);
map.locate({setView: true, maxZoom: 16});
map.on('click', onMapClick);
}
function onLocationFound(e) {
var radius = e.accuracy / 2;
L.marker(e.latlng).addTo(map)
.bindPopup("Position: " + e.latlng + " Genauigkeit " + radius ).openPopup();
L.circle(e.latlng, radius).addTo(map);
}
function onLocationError(e) {
alert(e.message);
}
function onMapClick(e) {
marker = new L.marker(e.latlng, {id:uni, icon:redIcon, draggable:'true'});
marker.on('dragend', function(event){
var marker = event.target;
var position = marker.getLatLng();
alert(position);
marker.setLatLng([position],{id:uni,draggable:'true'}).bindPopup(position).update();
});
map.addLayer(marker);
}
//var x = document.getElementById("demo");
function getLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition);
} else {
//x.innerHTML = "Geolocation is not supported by this browser.";
}
}
function showPosition(position) {
//x.innerHTML = "Latitude: " + position.coords.latitude +
//"<br>Longitude: " + position.coords.longitude;
}
http://imgur.com/exOUZuT
I would guess that the size of the map upon initialization is the culprit.
Leaflet needs to know the size of the element it is embedded in when initializing. Leaflet uses that information to know how much tiles to load etc. Furthermore any programmatic changes (or changes that cannot be easily detected by Leaflet) to the size of the map have to be followed by map.invalidateSize(..) link.
I suspect that after you set the size, Leaflet fails to read properly the new size of the #map element. Try invalidating the size afterwards or run initialization asynchronously. I would add:
setTimeout(function () {
map.invalidateSize();
}, 0);
and check if it gets any better.
I used that command to fix my missing tiles problem:
map.getSize();
Look like Leaflet needs to know the size of the element map in advance as Michal said.

Leaflet Clustering with multiple layers (use MarkerCluster.LayerSupport?)

Alright, so I've tried and failed a number of times and dug through SE hoping to figure out my problems.
I've been basing a lot of my work off this SE post: link.
I have been unable to make this work, mainly because of two errors, but the first one being an obvious hurdle to overcome first:
Error 1:
Uncaught SyntaxError: Unexpected token <
Error 2:
Uncaught TypeError: L.markerClusterGroup.layerSupport is not a function
So, I would like clustering to work with any layer that is turned on via the L.control.layers() function.
Here is my page, as it sits now: TN Alcohol Map
And the code, sans headers/misc:
// initialize the map
var map = L.map('map').setView([36.17, -86.78], 7);
// load a tile layer/base map
L.tileLayer('http://stamen-tiles-{s}.a.ssl.fastly.net/terrain/{z}/{x}/{y}.png',
{
attribution: 'Map tiles by Stamen Design, CC BY 3.0 — Map data © OpenStreetMap',
maxZoom: 18,
minZoom: 7
}).addTo(map);
//attributes for basemap credit (lower right hand corner annotation)
var streetsAttr = 'Map tiles by Stamen Design, CC BY 3.0 — Map data © OpenStreetMap';
var aerialAttr = 'Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community';
var artsyfartsyAttr = 'Map tiles by Stamen Design, CC BY 3.0 — Map data © OpenStreetMap';
//crete variables for the base map layer switcher
var streets = L.tileLayer('http://stamen-tiles-{s}.a.ssl.fastly.net/terrain/{z}/{x}/{y}.png', {id: 'MapID', attribution: streetsAttr}),
aerial = L.tileLayer('http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {id: 'MapID', attribution: aerialAttr}),
artsyfartsy = L.tileLayer('http://stamen-tiles-{s}.a.ssl.fastly.net/toner/{z}/{x}/{y}.png', {id: 'MapID', attribution: artsyfartsyAttr});
//create baseMaps variable to store basemap layer switcher
var baseMaps = {
"Streets": streets,
"Aerial": aerial,
"ArtsyFartsy": artsyfartsy
};
// BEER icon & load beer geojson
var beerIcon = L.icon({
iconUrl: 'glass.png',
iconSize: [24, 48]
});
var beerMarker = L.geoJson(false, {
pointToLayer: function(feature, latlng) {
var marker = L.marker(latlng, {
icon: beerIcon
});
//popup shows NAME, ADDRESS, URL and opens the URL in a new window/tab
marker.bindPopup("<strong>" + feature.properties.NAME + "</strong><br/>" + feature.properties.STREETNUM + " " + feature.properties.STREET + ", " + feature.properties.CITY + "<br/>" + "<a target = _blank href=" +
feature.properties.URL + ">" + feature.properties.URLDISPLAY + "</a>");
return marker;
}
}).addTo(map);
$.getJSON("breweries.geojson", function(data) {
beerMarker.addData(data);
});
// WINE icon & load wine geojson
var wineIcon = L.icon({
iconUrl: 'wine.png',
iconSize: [48, 48]
});
var wineMarker = L.geoJson(false, {
pointToLayer: function(feature, latlng) {
var marker = L.marker(latlng, {
icon: wineIcon
});
//popup shows NAME, ADDRESS, URL and opens the URL in a new window/tab
marker.bindPopup("<strong>" + feature.properties.NAME + "</strong><br/>" + feature.properties.STREETNUM + " " + feature.properties.STREET + ", " + feature.properties.CITY + "<br/>" + "<a target = _blank href=" +
feature.properties.URL + ">" + feature.properties.URLDISPLAY + "</a>");
return marker;
}
}).addTo(map);
$.getJSON("wine.geojson", function(data) {
wineMarker.addData(data);
});
//Define overlay maps (non-base layer maps)
var overlayMaps = {
"Breweries": beerMarker,
"Wineries": wineMarker
};
//Creates a Marker Cluster Group
var mcg = L.markerClusterGroup.layerSupport().addTo(map);
//Checking in the 'sub groups'
mcg.checkIn([
beerMarker,
wineMarker
]);
//baseMaps layer switcher
L.control.layers(baseMaps, overlayMaps).addTo(map);
As said by nathansnider in the question comment, the content of your leaflet.markercluster.layersupport-src file is not the JavaScript code of the markerCluster.LayerSupport plugin, but the GitHub HTML page that displays the code of that file, i.e. surrounded by plenty HTML code.
You should simply replace the content of your file by the content of the raw file here: https://raw.githubusercontent.com/ghybs/Leaflet.MarkerCluster.LayerSupport/master/leaflet.markercluster.layersupport-src.js
Demo: http://plnkr.co/edit/Jd8skZ1U0bWxgl2orJV6?p=preview
Side note:
If you just need the Layers Control to work with Leaflet.markercluster, there is another plugin that does just that and which is much simpler: Leaflet.FeatureGroup.SubGroup (230 lines of code v.s. 600 lines for Leaflet.MarkerCluster.LayerSupport as of today).
In your case you would use it this way:
// Create a normal Marker Cluster Group.
var mcg = L.markerClusterGroup().addTo(map);
// Create SubGroups.
var beerMarkerSub = L.featureGroup.subGroup(mcg).addTo(map);
var wineMarkerSub = L.featureGroup.subGroup(mcg).addTo(map);
// For Layers Control.
var overlayMaps = {
"Breweries": beerMarkerSub,
"Wineries": wineMarkerSub
};
// That is it! No need to check-in.
Code specific for your application, since you load GeoJSON data by AJAX:
var beerMarker = L.geoJson(null, beerOptions); // DO NOT add to map.
var wineMarker = L.geoJson(null, wineOptions); // Same story.
$.getJSON("breweries.geojson", function(data) {
beerMarker.addData(data); // GeoJSON conversion.
// Then transfer all features into the corresponding sub-group.
beerMarker.eachLayer(function (layer) {
layer.addTo(beerMarkerSub);
});
});
$.getJSON("wine.geojson", function(data) {
wineMarker.addData(data); // GeoJSON conversion.
// Then transfer all features into the corresponding sub-group.
wineMarker.eachLayer(function (layer) {
layer.addTo(wineMarkerSub);
});
});
Demo: http://plnkr.co/edit/x8vTLjE53TPiLd52BQ1d?p=preview
Disclosure: I am the author of these plugins.

create web map layers from multiple mbtiles on multiple servers

I'm using this http://blog.carte-libre.fr/index.php?post/2012/02/12/Serve-all-MBTtile-features-with-PHP-script to create a web map with mbtiles hosted on my server.
I want to create selectable layers using several mbtiles (mb1, mb2, mb3) which are stored on different servers (serv1, serv2, serv3).
The script is
wax.tilejson(
'mbtiles-server.php?db=mb1.mbtiles',
function(tilejson) {
var omq = new L.TileLayer(
'http://otile2.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png', {
maxZoom: 14,
attribution: 'OpenStreetMap - MapQuest',
opacity: 0.4,
});//modify to call mb2 from serv3
var power = new L.TileLayer(
"mbtiles-server.php?db=mb1.mbtiles&z={z}&x={x}&y={y}", {
maxZoom: 14,
attribution: 'OpenStreetMap - CL 2012-02-05',
});
var map = new L.Map('map', {
center: new L.LatLng(46, 0),
zoom: 6,
layers: [omq, power]
});
map.addControl( new L.Control.Layers( { "OpenMapQuest": omq }, { "Power": power }));
wax.leaf.interaction(map, tilejson);
document.getElementById("legend").innerHTML = tilejson.legend;
});
Assuming there is a php script file in each mbtiles folder, how can I modify the script to be able to call mb2 from serv3 so that i have 2 layers from 2 mbtiles hosted on 2 servers?
any advice would be welcomed!
An update...
The issue was trying to load several mbtiles while having respective popup interactions for each layer (each mbtile included interaction, created in TileMill).
I opted to load the mbtiles to the map using:
var base1 = L.tileLayer("http://ms1.mysite.com/folder1/mbtiles-server.php?db=base1layer.mbtiles&z={z}&x={x}&y={y}.png"
var base2 = L.tileLayer("http://ms2.mysite.com/folder2/mbtiles-server.php?db=base2layer.mbtiles&z={z}&x={x}&y={y}.png"
Then added interaction from a separate geojson file.
var onEachFeature_Polygon = function (feature, layer) {
//polygon geojson file contains center points
var centerLat = feature.properties.y;
var centerLon = feature.properties.x;
var centLatLon = new L.LatLng(centerLat, centerLon); //this is used to place the popup in the "mouseover" function
layer.setStyle(tooltip_default_style);
if (feature.properties && feature.properties.Name) {//fields Name, Population, RI10K
var list = "<b>" + feature.properties.Name + "</b>" + "<br>" + "<i>" + "Population: " + feature.properties.Population + "</i>" + "<br>" + "<i>" + "Income 10,000+: " + feature.properties.RI10K + "</i>" + "<br>";//end of tooltip list
layer.bindPopup(list);
}
layer.on("mouseover", function (e) {
layer.setStyle(tooltip_hover_style);
layer.openPopup(centLatLon);
});
layer.on("mouseout", function (e) { layer.setStyle(tooltip_default_style) });
}
//this is the onEachFeature function called when the statsJSON layer is added to the map
var statsinteractive = new L.GeoJSON(statsgeo, { onEachFeature: onEachFeature_Polygon });
statsinteractive.addTo(map);
Would still like to understand or be directed to a clearly outlined method to 'call' interaction from an mbtile file.
In the meantime, I hope this is helpful for someone with a similar issue.

OpenLayers: Open popup when hovering vector, without closing it when mouse is over popup itself

I have a map with a vector layer showing features from GeoJSON. When I hover the feature, a pop-up shows up at the beginning of the linestring. But it is flickering, it appears and disappears. I guess the feature somehow gets deselected. Maybe popup gets in the middle between mouse and the feature so the condition of feature being hovered is no more fulfilled. How can I solve it? I want the pop up to be displayed when the mouse is over the feature, no matter if the popup is in the way.
I think it can be replicated even with example code: http://openlayers.org/dev/examples/light-basic.html .
It happens even if my mouse is not directly over the white part of the popup.
It seems to me the problem is more severe in chrome than in firefox. Maybe this is not the problem of my code, but bug. If so, sorry for posting here.
I am using foollowing code :
layer = new OpenLayers.Layer.Vector("JOSM", {
eventListeners: {
'featureselected': function(evt) {
var feature = evt.feature;
var detailsTextHtml = "";
var lines = feature.attributes.evaluations.split("\n");
for (var i = 0; i < lines.length; i++) {
if (lines[i] !== "") {
detailsTextHtml += " <br> " + lines[i];
}
}
popup = new OpenLayers.Popup.FramedCloud("popup",
OpenLayers.LonLat.fromString(feature.geometry.getVertices()[0].toShortString()),
null,
"<div style='font-size:.8em'>Coefficient: " + feature.attributes.coefficient + "<br>Color:" + feature.attributes.color + "<br>Details: " + detailsTextHtml + "</div>",
null,
true
);
feature.popup = popup;
map.addPopup(popup);
},
'featureunselected': function(evt) {
var feature = evt.feature;
map.removePopup(feature.popup);
feature.popup.destroy();
feature.popup = null;
}
},
styleMap: styleMap,
strategies: [new OpenLayers.Strategy.Fixed()],
projection: geographic,
protocol: new OpenLayers.Protocol.HTTP({
url: "webresources/getJosmAspectsDetailed?startLon=" + document.getElementById('startLon').value +
"&startLat=" + document.getElementById('startLat').value +
"&endLon=" + document.getElementById('endLon').value +
"&endLat=" + document.getElementById('endLat').value + "&speed=17&comfort=0&quietness=0",
format: new OpenLayers.Format.GeoJSON()
})
});

Google Maps API v3 marker setPosition not working in Safari (sencha touch)

I am using Sencha Touch to develop a mobile version of a Bus Tracker for Boston University. The problem I a running into is that the method setPosition() for a google.maps.Marker is not rendering the position change in Safari or any Mobile browser.
The code set up is as follows:
I initialize an empty markers array
I initialize the map using Ext.Map() (sencha call)
I load data using a JSONP request every 5 seconds interval
Every time I get new data, I check if I have a marker for that bus id inside my markers array
If I don't I create a new marker and push it into my markers array
Otherwise I call setPosition with my new position on that marker in my markers array.
I then run a check to make sure the marker's position got updated to the position received from my JSON request
I have verified (I think) that the marker inside the markers array is getting the new position everytime. Also, in Chrome and Firefox, my buses move (as expected), but in safari and iPhone/Android browsers, nothing moves.
Here is the code snippet:
var markers = {};
var busesFunc = function()
{
Ext.util.JSONP.request({
url: 'http://m.cms-devl.bu.edu/rpc/bus/livebus.json.php',
callbackKey: 'callback',
params: {
},
callback: function(data) {
buses = data.ResultSet.Result;
for (var i = 0, ln = buses.length; i < ln; i++) {
var bus = buses[i];
var position = new google.maps.LatLng(bus.lat, bus.lng);
if(!markers[bus.id])
{
markers[bus.id] = new google.maps.Marker({
map: map.map,
title: 'hello',
clickable: true,
draggable: false,
position: position,
icon: "images/bg.png",
zIndex: 100
});
}
markers[bus.id].setPosition(position);
//markers[bus.id].setIcon("images/bg.png");
//markers[bus.id].setMap(map.map);
//markers[bus.id].setMap(map.map);
if(bus.lat != markers[bus.id].position.lat() || bus.lng != markers[bus.id].position.lng())
{
console.log(bus.id + " " + bus.lat + " " + bus.lng);
console.log(bus.id + " " + markers[bus.id].position.lat() + " " + markers[bus.id].position.lng());
}
}
}
});
}
setInterval(busesFunc, 5000);
You can view the sample here: http://www.bu.edu/nisdev/students/luiscarr/liveBusMobile/
And the whole javascript is called functions.js (I can't post more than one link)
[Sencha Person] markers not showing up is a known bug in the 0.93 beta release. The 0.94 release (current one) has this fixed.
Problem solved by making a unique request every interval. I figured it was a caching problem after some more debugging. So I added a timestamp parameter to the JSONP request and it was all fixed.