floatleft
floatleft

Reputation: 6541

Google Maps JS: pinch to zoom Google Maps without moving marker (ie. Uber & Lyft)

I'm currently building a Phonegap app along with Google's Map JS API.

I have a map that you can drag to select your dropoff location. This is accomplished by collecting the map's center geolocation on the "dragend" event. I then set a pin on top of the map (outside of the JS map) so that you know where the center point is.

Everything works fine until you pinch to zoom and the pin is then displaced. This is due to you zooming and dragging the map at the same time when pinching the screen.

Is there any way to prevent dragging on zoom in order to hold the map at its center point?

Please view the JSfiddle here.

var map;
google.maps.event.addDomListener(window, 'load', onMapReady);


function onMapReady() {

    var center = new google.maps.LatLng(30.267153, -97.743061);
    var mapOptions = {
        center: center,
        zoom: 13,
        styles: [{"featureType": "poi", "stylers": [{ "visibility": "off" }]},{"featureType": "transit","stylers": [{ "visibility": "off" }]}],
        disableDefaultUI: true,
    };

    map = new google.maps.Map(document.getElementById('map'), mapOptions);

    google.maps.event.addListener(map, 'dragend', function() {
        center = map.getCenter();        
        $('#log').html('Lat: ' + center.lat() + ' Lng: ' + center.lng());
    });
}

Upvotes: 4

Views: 1779

Answers (3)

ProllyGeek
ProllyGeek

Reputation: 15836

There are two possible solutions for this issue , from what i have read that you have tried using native marker but it is lagging , which itself is another issue that i have a suggestion for :

  1. use crosswalk for building your app , this will extremely boost your app performance , i have experienced it myself , and was really satisified with results ( iam using intel xdk but i believe this will work for phonegap as well ).

  2. use the UX solution : you feel the marker is lagging because after all it is visible !! i would suggest hiding the marker on drag event start , then showin it back on drag event end.

  3. Third solution which makes sense , is using a pinch detector library like this , this , or even solutions mentioned here , and here , pick whatever works best for you , as performance is a point of concern , and previous solution have to be tried , however once you have detected the pinch gesture , you set the map drag to false , set it back again to true after pinch ends .

I dont usually provide much coding in my solution but rather the correct algorithm to help solving the specified issue.

Upvotes: 2

Kay_N
Kay_N

Reputation: 997

I have a solution which might work. Assuming you want the map to center back to the pin.

Add custom control div in your map object. The example is here. Instead of the "center map" div in the example, make your pin the controlling div. Listen to dragend event and set the center at pin's position.

Haven't really tested the solution but seems like it will do the trick.

Upvotes: 1

pherris
pherris

Reputation: 17703

EDIT: ProllyGeek is right, the zoom_changed event fires after the drag has already happened. You can detect if the touch event was near the center of the map (over your marker) and re-center the map after zooming:

google.maps.event.addListener(map, 'dragend', function() {
    if (center && center != map.getCenter()) {
        map.setCenter(center);
        center = null;
    }
});

//we should recenter the map if the click/mousedown was within the centerRadius of the center of the map
google.maps.event.addListener(map, 'mousedown', function(clickMouseEvent) {
    var mapDiv = document.getElementById('map');

    if (pointInCircle(clickMouseEvent.pixel.x, 
                      clickMouseEvent.pixel.y, 
                      mapDiv.offsetWidth/2, 
                      mapDiv.offsetHeight/2, 
                      centerRadius)) { 
        //map.setOptions({draggable: false}); //disables zoom and dragging
        center = map.getCenter(); //save the current center point so we can recenter later.
    }
});

//handy function to see if a x,y coordinate is within z radius of another x,y coordinate
//from https://stackoverflow.com/a/16819053/1861459
function pointInCircle(x, y, cx, cy, radius) {
    var distancesquared = (x - cx) * (x - cx) + (y - cy) * (y - cy);
    return distancesquared <= radius * radius;
}

http://jsfiddle.net/bxfn499f/11/

Original Answer:

Did you try setting draggable to false on the map when the zoom event is fired?

google.maps.event.addListener(map, 'zoom_changed', function() {
    map.setOptions({draggable: false});
    //heavy handed re-enabling of draggable
    //setTimeout(function() { map.setOptions({draggable: true}); }, 5000); //cant drag for five seconds
});

You can programmatically re-enable dragging with the mouseup event (which should fire in lieu of the touchend event) or whatever makes sense in your use case (map.setOptions({draggable: true});). For example:

google.maps.event.addListener(map, 'mouseup', function() {
    map.setOptions({draggable: true});
});

http://jsfiddle.net/bxfn499f/6/ I tested from a desktop, so I tweaked the fiddle slightly as the map wasn't loading for me - assuming this was due to the window.load not being fired after $(document).ready(function() { ... }. You'll have to see how this behaves if the drag stars before the zoom event.

Upvotes: 1

Related Questions