4

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());
    });
}
floatleft
  • 6,243
  • 12
  • 43
  • 53
  • Questions: 1) Why don't you use a `google.map.Marker` that would stay at the same location? 2) Is this supposed to happen only once or every time the user stops dragging the map? – MrUpsidown Mar 24 '15 at 15:14
  • I use getCenter(); with a superimposed marker instead of an actual marker because the marker lags/jumps if you update a marker location to the center of the map as you drag the map. – floatleft Mar 24 '15 at 15:23
  • 1
    The marker *lags/jumps*? I see no reason why this would happen. – MrUpsidown Mar 24 '15 at 16:14
  • @MrUpsidown Here is an example: http://jsfiddle.net/pLq8s4xt/ And it the performance is worse on mobile, and experiences the same issue of the marker moving when you pinch-to-zoom. – floatleft Mar 25 '15 at 22:27

3 Answers3

2

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.

Community
  • 1
  • 1
ProllyGeek
  • 15,517
  • 9
  • 53
  • 72
1

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.

Community
  • 1
  • 1
pherris
  • 17,195
  • 8
  • 42
  • 58
  • Hey down-voter - please help me understand how this does not answer the question "Is there any way to prevent dragging on zoom in order to hold the map at its center point?" – pherris Mar 24 '15 at 15:20
  • 1
    I popped this in my code and it didn't preform as intended. Great idea, just doesn't work in practice. – floatleft Mar 24 '15 at 15:29
  • 1
    Would you explain the problem you encountered? I was working on an edit which uses the mouseup event to reenable the draggable attribute - you might want to check that out. FYI: "Use your downvotes whenever you encounter an egregiously sloppy, no-effort-expended post, or an answer that is clearly and perhaps dangerously incorrect." – pherris Mar 24 '15 at 15:32
  • I didn't downvote you. I only commented on your code. Sorry for the misunderstanding. – floatleft Mar 24 '15 at 18:55
  • No worries! someone wants that bounty ;) - anyway, let me know what issues you had with the suggested approach and if the mouseup approach works for re-enabling the draggable attribute of the map. – pherris Mar 24 '15 at 19:06
  • i was about to vote this up , but have you thought that zoom changed takes place on gesture end , you need something to detect gesture start , some modifications will make your solution nice. – ProllyGeek Mar 27 '15 at 12:02
  • @ProllyGeek Yes, you are right - the event order doesnt make this quite possible. I tested disabling draggable if the mousedown event was over the center of the map, but disabling draggable also seems to disable zoom. – pherris Mar 27 '15 at 15:56
  • @pherris +1 for modification – ProllyGeek Mar 29 '15 at 14:51
  • @floatleft can you tell me how you solve this pinch zoom issue ? – Sunny Goel Dec 28 '21 at 14:15
1

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.

Kay_N
  • 987
  • 5
  • 12