In my google maps application I have a follow method which follows a moving marker. When it is following I want to allow zooming through all the usual methods (dblclick, dblleftclick, mousewheel and touch events) and I want to disable panning of any kind. The problem is that on zoom with mousewheel and dblclick the map gets panned to the position of the mouse. I can disable everything just fine but I want to allow zooming. I have solved the mousewheel problem by using the jquery mousewheel plugin and using the delta to change the zoom.
Is there some easy way to do this or do I have to write a listener for all the different touch and mouse events?
EDIT
I have already disable double click, mousewheel zooming and dragging but I want to have the double click functionality still there. I also want the touch events there but I want to have them zoom from the centre rather than from where the event happened. The real problem is replicating the events which google already handle but change the functionality a bit
var options = {
disableDoubleClickZoom: true,
draggable: false,
scrollwheel: false,
panControl: false
};
this.map = new google.maps.Map(document.getElementById('map'), options);
My ideal solution would be if there was a disableDoubleClickPan and disableScrollwheelPan or the draggable option actual prevents all dragging of any kind
EDIT
This is for all devices, desktop and mobile.
Here is how I did it:
var options = {
draggable: false,
scrollwheel: false,
panControl: false,
maxZoom: Zoom,
minZoom: Zoom,
zoom: Zoom,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
As you can see, setting maxZoom and minZoom to the same value helps block user's double click event.
I have ended up going with a combination of options. Firstly I had to override desktop events which occurred to get my achieved result (touch, double click, double left click, and mouse wheel).
On a touch screen devise I paused all updates to the markers when there were more than two touches. this meant that any pinch event was not jumping around when the zoom operating.
On a normal web desktop device I disabled the zoom and double click events on the map and rewrote my own event handlers.
To distinquish between them I checked for the ontouchstart event in the window object.
function setDraggable(draggable) {
if ("ontouchend" in document) {
return;
}
var options = {
draggable: draggable,
panControl: draggable,
scrollwheel: draggable
};
this.map.setOptions(options);
},
The zoom_changed or idle events where not really an option for a few reasons:
The idle event only gets called when the map is idle and with the amount of animation I was doing this never got called.
The animation at each step recentered the map on the followed markers so the zoom_changed event would be recalling the recenter before an animation frame.
due to the amount of animation the idea of not panning to the center is to reduce animation frames and improve performance.
While it's possible to argue that double-clicking the map or wheel-zooming the map need not take account of the mouse location (because you are acting on the map object rather than a location on the map), pinch-to-zoom is always location-dependent because you physically stretch or squash the map around a location. To alter that behaviour would be distinctly unintuitive.
In this case you should listen for zoom_changed or idle and then pan the map to recentre it, so the user can see what's going on.
You could even use those events to handle the default double-click or mousewheel behaviour so that it's obvious you are changing the level of control the user normally has.
Related
I'd like to perform a pan and zoom effect from one marker to another. For example if the current view is {lat:m1.lat, lng:m1.lng, zoom:13}, I would do something like this:
//Zoom out to initial position
map.setView([center.lat, center.lng], 13, { animate: true });
and at the end of transition...
//Zoom in to new marker
map.setView([m2.lat,m2.lon],18,{animate:true});
Unfortunately, the zoom effect is too fast. So, can I get a smooth zoom?
Use flyTo, available in Leaflet 1.0.0-rc1.
I have a big problem for mobile users:
i have a google maps that has width: 100% and so when the user scroll the window if touch the screen "inside" the map, the scroll it will be only for map and not for all window... (yesterday my father for 3 minutes scrolled inside the map XD)
To scroll the window is possible touch the border of screen, but is very very scrict and not all users understand this.
I dont'want a map with a width less of 100% so i must found other solution...
This is it will be make the map draggable only when it is touch with two fingers, almost when pinch to zoom...
but which google maps event i can to use ?
maybe:
google.maps.event.addListener(map, 'dblclick', function(event){
this.setOptions({draggable:true});
});
but maybe at first click on map i should to alert (with a div in map) that is possible to move the map with two fingers ??
What do you think? and code is correct?
Thanks a lot and sorry for my english and for strange question :D
If you are using API v3.27 or higher. While initializing map just add property gestureHandling: 'Cooperative'
like this
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 4,
center: myLatLng,
gestureHandling: 'cooperative'
});
More Info Here
Or if you want to do this after creating the map, do
map.setOptions({gestureHandling: 'cooperative'});
More Info Here
Although this is quite strange requirement, you can try the following;
document.addEventListener('touchmove', function(e) {
e.preventDefault();
var touch = e.touches[0];
if(e.touches.length == 2){
//This means there are two finger move gesture on screen
googleMapsReference.setOptions({draggable:true});
}
}, false);
I have not tested this on a mobile device but it should give you a starting point.
I have a google map with drawing overlays for rectangle, circle, polygon. Everything is cool but I want to clear the overlays before I start drawing a new one (automatically).
There doesn't seem to be any way to clear it via an existing Google Maps control and I don't want to create some custom button for it.
google.maps.event.addListener(this.map, 'mousedown', function(event) {
console.log('map mousedown');
console.log(_this.drawingManager.getDrawingMode());
});
I'm trying to clear the maps when a mousedown event occurs on the map. But it seems when the map is in "drawing mode" this event doesn't fire. I also can't find any documentation on any kind of mouse events for the drawing control.
Is there a way to fire a mousedown even when in drawing mode (drawing a circle, rectangle, polygon, etc) ?
There isn't a way to fire a mousedown event on map when in drawing mode I know of, but still I think there are two possible ways for you to go:
A. Only if you are using custom buttons for drawing manager (meaning you set drawingControl: false when initializing DrawingManager and create your own buttons). Then, when any drawing button was pressed, e.g. button for drawing a polyline, you can listen for the event which is fired when drawing was complete, and setDrawingMode to null which ensures that user will have to click one of the icons again to start drawing, where you can in the same click listener delete all existing drawings. For example (illustrational, depends on your setup):
$('#polylineButton').on('click', function(){
//delete any previous existing drawings on map
drawing_manager.setDrawingMode(google.maps.drawing.OverlayType.POLYGON);
google.maps.event.addListenerOnce(drawing_manager, 'overlaycomplete',function(polyline) {
drawing_manager.setDrawingMode(null); //set to hand cursor after overlay was drawn
..
}
...
});
So this solution wouldn't require any additional buttons on the map, only those required to select respective drawing tools (hand, polyline, circle, etc.)
B. You cannot listen for the map click event, but you can still listen for a click event on the div containing the map. In that case you can, also with leveraging overlaycomplete event, set up some variables indicating when drawing started. Something similar to what was done in this answer .
I'm using Angular(UI)-Google-Maps (2.1.5) and AngularJS (1.3.13)
I want a marker that is always in the center of the map. The problem is that the marker only updates its position when I stop dragging.
I use the drag event like this:
drag: function(maps) {
$scope.map.marker.center.coords = $scope.map.center;
}
I also count the amount, how often the drag event triggers, which is much higher than the updates of the marker (or map). Here's an example: http://plnkr.co/edit/M39CFc
I also tried center_changed and bounds_changed with the same result.
To put the marker in the center of the map make use of the following tag:
<ui-gmap-marker coords="map.center" idkey="1" ng-cloak>
Although this technique is discouraged as it will also move the marker when the map is dragged. To get a workaround with this situation use:
marker.coords = Object.create(coords)
Another possibility is to add the property draggable = true to the markers:
<ui-gmap-markers coords="'self'" icon="'icon'" options="{ draggable: true }">
Don't know why this solve the issue in IE, check this
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());
});
}
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 :
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 ).
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.
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.
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.
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.