Google Map mouse wheel bug - javascript

Normally it's possible to scroll / zoom vertically out of the map. There would be a grey background. I "disabled / blocked" that.
This works fine if I use the controls from Google map. But if I zoom with the mouse wheel it's kinda buggy and I can zoom out of the map, so the grey area is visible.
Here is a live example: Example
How could I fix that without disabling the mouse wheel zoom?
Image:
THEME.gmap.position = function () {
var allowedBounds;
var lastCenter;
var lastZoom;
var initCenter;
var initZoom;
function checkBounds() {
if (THEME.base.isUndefined(allowedBounds)) {
return false;
}
if (allowedBounds.getNorthEast().lat() > THEME.gmap.google_map.getBounds().getNorthEast().lat()) {
if (allowedBounds.getSouthWest().lat() < THEME.gmap.google_map.getBounds().getSouthWest().lat()) {
lastCenter = THEME.gmap.google_map.getCenter();
lastZoom = THEME.gmap.google_map.getZoom();
return true;
}
}
THEME.gmap.google_map.panTo(lastCenter);
THEME.gmap.google_map.setZoom(lastZoom);
return false;
}
return {
createLatLng:function (lat, lng) {
return new google.maps.LatLng(lat, lng);
},
centerMap:function (latLng) {
THEME.gmap.google_map.setCenter(latLng);
},
setLimit:function () {
allowedBounds = new google.maps.LatLngBounds(
this.createLatLng(-85.0511, -122.591),
this.createLatLng(85.0511, -122.333)
);
initCenter, lastCenter = THEME.gmap.google_map.getCenter();
initZoom, lastZoom = THEME.gmap.google_map.getZoom();
google.maps.event.addListener(THEME.gmap.google_map, 'bounds_changed', function () {
checkBounds();
});
google.maps.event.addListener(THEME.gmap.google_map, 'center_changed', function () {
checkBounds();
});
}
};
}();

I guess this is forced by the 2 competing events, usually both event will fire each time. As the center_changed event is redundant(the bounds also will change when the center changes), you may remove the center_changed-listener(for me this also fixes the issue)

Related

Google Maps losses mousemove Event Listener after simultaneous dragstart and dragend events

I am working over a Google Map API application, but I got into a bug where mousemove event listener is lost after a mousedown event. It restores activity if the map is dragged or zoomed. Please check this simple example here, where the problem can be replicated after you click on the map for a while:
https://jsfiddle.net/dninov81/95ybk1wt/31/
let map;
let marker;
const textField = document.getElementById('text')
function initialize() {
map = new google.maps.Map(document.getElementById('map-canvas'), {
center: {
lat: 52.50871874907,
lng: 6.2503252411254
},
mapTypeId: google.maps.MapTypeId.ROADMAP,
zoom: 15,
})
map.addListener( 'mousemove', onDrawMove);
map.addListener( 'mousedown', onDrawDown);
}
initialize();
function onDrawMove(e) {
textField.innerHTML = e.latLng
}
function onDrawDown(e) {
textField.innerHTML = e.latLng
if(marker) {
marker.setMap(null)
}
marker = new google.maps.Marker({
position: e.latLng,
map: map
});
marker.setMap(map);
}
Here is a record of the problem, where when mouseover listener is active we can see the coordinates are correctly displayed in the text field and once it stops, only the mousedown event is registered. After a zoom change the mouseover event resumes.
https://youtu.be/gb3A83g4Qt0
If anyone experience similar behavior I would like to know why is this?
UPDATE:
We managed to isolate the problem and it accurses when dragstart and dragend events are fired simultaneously due to fast clicking sometimes. Still the problem persist it also occurs in google official event handling tool here:
https://developers.google.com/maps/documentation/javascript/events
It turns out it is a known bug and here is the solution from the issue tracker:
var dragStartCenter = null;
google.maps.event.addListener(map, "dragstart", function() {
dragStartCenter = map.getCenter();
});
google.maps.event.addListener(map, "dragend", function() {
if (dragStartCenter && dragStartCenter.equals(map.getCenter())) {
// execute panBy() if the map has not been moved during dragging.
map.panBy(0, 0);
}
});

Markkers are displayed twice with Leaflet search

I've made a map, based on a geojson file and with clustered markers.
Then I tried to add the leaflet-search plugin.
The search feature works : when I search somtehing, it opens the good popup (informations are generated by "complex" routines).
But now I have my markers displayed twice : the ones I previously created, then those displayed by the search plugin.
How to make leaflet-search to not display its own markers ?
I hope I was clear enough. Bellow here is a sample of my code (I tried to made it readable) :
var geojsonFeature = { mygeojsondata };
// Runs several function to generate an "information page" for each feature
function createPopupInfo(feature, layer) {
var pop = render_name(feature);
//
// ...
}
var nbfeatures = 0;
var layer1 = new L.geoJSON(geojsonFeature, {
onEachFeature: createPopupInfo,
pointToLayer: function (feature, latlng) {
nbfeatures++;
var marker = L.marker(latlng)
arrayOfLatLngs.push(latlng);
marker.on("add", function (event) {
// Retrieve the layer through event.target http://leafletjs.com/reference-1.0.0.html#event-target
event.target.openPopup();
var latLngs = [marker.getLatLng()];
var markerBounds = L.latLngBounds(latLngs);
map.fitBounds(markerBounds);
});
map.maxBoundsViscosity = 0;
return marker;
}
});
var searchControl = new L.Control.Search({
layer: layer1,
propertyName: 'search_index',
marker: false,
moveToLocation: function (latlng, title, map) {
map.setView(latlng, 17);
}
});
searchControl.on('search:locationfound', function (e) {
if (e.layer._popup)
e.layer.openPopup();
}).on('search:collapsed', function (e) {
layer1.eachLayer(function (layer) { //restore feature color
layer1.resetStyle(layer);
});
});
// Clustering
var markers = L.markerClusterGroup();
markers.addLayer(layer1);
map.addLayer(markers);
When the search finds something, harness that event to remove the layer with all the markers:
searchControl.on('search:locationfound', function (e) {
if (e.layer._popup) e.layer.openPopup();
markers.removeLayer(layer1)
})
Of course you'll also want to add these markers back in when you close the search:
searchControlon('search:collapsed', function (e) {
markers.addLayer(layer1);
layer1.eachLayer(function (layer) { //restore feature color
layer1.resetStyle(layer);
});
});
I would say its good UX to also add them all back in when the search comes up empty, but theres' no obvious event for that with leaflet-search.
I found what didn't work, I must pass the "clustered layer" :
var searchControl = new L.Control.Search({
layer: markers,
propertyName: 'search_index',
...
Sources :
https://gis.stackexchange.com/questions/310797/using-l-control-search-and-l-markerclustergroup
https://github.com/stefanocudini/leaflet-search/issues/166
And another example :
http://embed.plnkr.co/46VJcp/

HERE API - map does not work in safari browser

im working on a PWA which retrieves the users location via geolocation-API, places a pin to the current location of the user and allows him to drag the pin to a certain location.
this works perfectly in chrome but when testing it in safari, the map only displays the whole world on
the map and doesnt allow zooming further than a few pinches + it doesnt place a marker.
// configure pin
function addDraggableMarker(map, behavior) {
// create icon
var svgMarkup = /* some random svg here */;
var icon = new H.map.Icon(svgMarkup);
// position the pin
var coords = {
lat: lat,
lng: lng
};
// initialize pin
window.marker = new H.map.Marker(
coords, {
icon: icon
}, {
volatility: true
}
);
// make pin draggable
marker.draggable = true;
map.addObject(marker);
// disable the default draggability of the underlying map
map.addEventListener('dragstart', function(ev) {
var target = ev.target,
pointer = ev.currentPointer;
if (target instanceof H.map.Marker) {
var targetPosition = map.geoToScreen(target.getGeometry());
target.offset = new H.math.Point(pointer.viewportX - targetPosition.x, pointer.viewportY - targetPosition.y);
behavior.disable();
}
}, false);
// re-enable the default draggability of the underlying map when dragging has completed
map.addEventListener('dragend', function(ev) {
var target = ev.target;
if (target instanceof H.map.Marker) {
behavior.enable();
window.markerMoved = target.getGeometry();
}
}, false);
// Listen to the drag event and move the position of the marker as necessary
map.addEventListener('drag', function(ev) {
var target = ev.target,
pointer = ev.currentPointer;
if (target instanceof H.map.Marker) {
target.setGeometry(map.screenToGeo(pointer.viewportX - target.offset.x, pointer.viewportY - target.offset.y));
}
}, false);
}
// click on the button which displays the map
$("#addLocation").on('click', function() {
// 1. connect to API
window.platform = new H.service.Platform({
'apikey': 'MY_API_KEY'
});
window.defaultLayers = platform.createDefaultLayers();
// 2. initialize map
window.map = new H.Map(document.getElementById('map'),
defaultLayers.vector.normal.map, {
center: {
lat: lat,
lng: lng
},
zoom: 16,
pixelRatio: window.devicePixelRatio || 1
});
// stretch map to size of container
window.addEventListener('resize', () => map.getViewPort().resize());
// 3. make map interactive
//Behavior implements default interactions for pan/zoom (also on mobile touch environments)
window.behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
// 4. add map UI
window.ui = H.ui.UI.createDefault(map, defaultLayers, "de-DE");
// Add the click event listener.
addDraggableMarker(map, behavior);
});
I copied your code into jsfiddle example and everything works as expected in Safari browser. After clicking the button "AddLocation" the map is displayed at correct location + zoom with marker at the center.
There is one small issue with your code when the Marker is created. volatility property should be next to the icon property:
new H.map.Marker(
coords, {
icon: icon,
volatility: true
}
);

FullscreenControl and Maintaining Map Center

Currently, it appears that if I have say a modestly sized Google Maps display port (300px by 300px) with FullscreenControl enabled, and I center that small map view over a specific area, like... France, for instance... And then I hit the full screen button to expand the display to the edges of my screen (1920px by 1080px), France gets tucked wayyyyy up in the top-left corner of my screen.
Basically, the top-left of the original 300px x 300px display moves to the top-left of my screen, and rest of the world map extends from that corner at the original zoom level.
Is there any way to basically just set it up so that the full screen display opens up having the same center point as the original display, and vice versa when the full screen mode gets closed?
Does toggling the full screen button trigger an event or anything that I can hook a setCenter to?
I compose a code a bit strange but it works perfectly:
<script>
var map;
var center = -1;
var isFullScreen = false;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
zoom: 8,
center: { lat: -34.397, lng: 150.644 }
});
center = { lat: map.getCenter().lat(), lng: map.getCenter().lng() };
google.maps.event.addDomListener(map, 'bounds_changed', onBoundsChanged);
}
function onBoundsChanged() {
var isFullHeight = $(map.getDiv()).children().eq(0).height() == window.innerHeight;
var isFullWidth = $(map.getDiv()).children().eq(0).width() == window.innerWidth;
if (isFullHeight && isFullWidth && !isFullScreen) {
isFullScreen = true;
map.setCenter(center);
console.log('FULL');
} else if (!isFullWidth||!isFullHeight){
if (isFullScreen) {
map.setCenter(center);
}
isFullScreen = false;
console.log('NOT-FULL');
}
center = { lat: map.getCenter().lat(), lng: map.getCenter().lng() };
}
</script>
I use the bounds_changed event.
If I detect that the map is in full screen I set the map in the center that I note in the precedent event and I set a boolean to true. If the map is not in full screen, I check if the boolean is true, it mean that in the precedent event the map was in full screen, so I recenter the map and next I check if the boolean is false. At the end of the event, I keep the center in a variable fro the next event.
All this are not very clear...
You may consult this post in Stack Overflow.
Notice: This code does not work if you display a single map in all the page of your web app. I do not find a way to remove this bug. Your suggestions are very appreciated, thanks.
Also notice: My code is inspired of the precedent answer. However you can find the same code here. Please notice that it is not a duplicate answer. I add my own part of code in it.
Tell me if you have some questions or comments.
Try this
/** To detect Map Full Screen event */
google.maps.event.addListener( map, 'bounds_changed', onBoundsChanged ); //Event listener map bound change.
var isMapFullScreen = false;
var defaultLocation = {
lat: 27.94,
lng: -82.45
};
function onBoundsChanged() {
if(!isMapFullScreen){
var isFullHeight = $(map.getDiv()).children().eq(0).height() == window.innerHeight;
var isFullWidth= $(map.getDiv()).children().eq(0).width() == window.innerWidth;
if (isFullHeight && isFullWidth) {
isMapFullScreen = true;
myMarker.setPosition(defaultLocation);
map.setCenter(defaultLocation);
console.log('FULL');
} else {
isMapFullScreen = false;
console.log('NOT-FULL');
}
}
}

Embed Google Maps on page without overriding iPhone scroll behavior

I'm working on optimizing a site for mobile. We have a Location page that includes info about a location and a map of the location via the Google Maps API. (v2 - I know it's deprecated but I haven't justified the time to upgrade, "if it ain't broke..") I want to use a single column layout with basic information followed by the map followed by more information.
Now when I use my finger to scroll down the mobile page on an iPhone, once I get to the map, the page scrolling is overridden and the map starts panning. The only way for me to scroll farther down the page is to put my finger above or below the map, assuming such space is available. If I disable map dragging, then when I start scrolling down and get to the map it doesn't pan but the page doesn't scroll either. I would like to treat the map as a static image that I can scroll past, but still allow the zoom buttons and allow the map to be redrawn with directions through a select field I have coded, so a literal static image is not a solution.
I found this post that required similar functionality, but it's using v3. I think all I need to do is "add touch events to the map container," but I'm not familiar with that part of javascript, and what I have below does not allow normal scrolling. Do I need to bite the bullet on v3, or do I have a bug on adding touch events that has a simple javascript correction to do what I want?
function initialize() {
if (GBrowserIsCompatible()) {
map = new GMap2(document.getElementById("map_canvas"));
geocoder = new GClientGeocoder();
}
}
function showAddress(address, zoom) {
//clipped... this part works fine
}
//These three lines create a map that my finger pans
initialize();
showAddress("[clipped.. street, zip code]");
map.addControl(new GSmallZoomControl3D());
//This stops the map pan but still prevents normal page finger scrolling
map.disableDragging();
//If done right could this allow normal page finger scrolling??
var dragFlag = false;
map.addEventListener("touchstart", function(e){
dragFlag = true;
start = (events == "touch") ? e.touches[0].pageY : e.clientY;
},true);
map.addEventListener("touchend", function(){
dragFlag = false;
}, true);
map.addEventListener("touchmove",function(
if ( !dragFlag ) return;
end = (events == "touch") ? e.touches[0].pageY : e.clientY;
window.scrollBy( 0,( start - end ) );
}, true);
I have also tried replacing map.addEventListener with document.getElementById("map_canvas").addEventListener or document.addEventListener to no avail.
I solved it by upgrading to v3 and then detecting a basic javascript error in my use of the code from the solution linked above. The key was
start = (events == "touch") ? e.touches[0].pageY : e.clientY;
The user must have been setting the events variable somewhere outside the presented code, since it looks like the matching assignment is for touch events and the else assignment is for key events. But since I didn't have an events variable it was defaulting to the wrong assignment. I simply changed mine to start = e.touches[0].pageY (and did the same for the touchend event) and now everything works.
However, I switched back to v2 to see if it would work with that javascript error corrected, and it did not. So it looks like I did not waste any time upgrading to v3, neither in figuring out this specific solution nor in setting myself up for future compatibility.
In conclusion, if you want to embed Google Maps on a mobile page and be able to scroll past it, you need to use API v3, disable dragging, and add touch events. I made a few minor tweaks to my code as well, presented here for any who may benefit in the future:
function initialize()
{
geocoder = new google.maps.Geocoder();
var myOptions = {
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
}
function showAddress(address, zoom)
{
if (geocoder)
{
geocoder.geocode( { 'address': address }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
map.setCenter(results[0].geometry.location);
map.setOptions( { zoom: zoom });
var marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location
});
}
});
}
}
initialize();
showAddress("'.$geocode_address.'");
map.setOptions( { draggable: false });
var dragFlag = false;
var start = 0, end = 0;
function thisTouchStart(e)
{
dragFlag = true;
start = e.touches[0].pageY;
}
function thisTouchEnd()
{
dragFlag = false;
}
function thisTouchMove(e)
{
if ( !dragFlag ) return;
end = e.touches[0].pageY;
window.scrollBy( 0,( start - end ) );
}
document.getElementById("map_canvas").addEventListener("touchstart", thisTouchStart, true);
document.getElementById("map_canvas").addEventListener("touchend", thisTouchEnd, true);
document.getElementById("map_canvas").addEventListener("touchmove", thisTouchMove, true);

Categories

Resources