pan with one finger - javascript

I want to prevent the user from panning while pinch rotating or zooming,
so the solution I have come with is to limit the user to pan only with one finger.
so I was able to do that with the following code:
var interactions = map.getInteractions().forEach(function(interaction) {
if (interaction instanceof ol.interaction.DragPan) {
pan = interaction;
}
}, this);
//disable pan with 2 fingers by redefine the handleDownEvent function and call
//to the original handleDownEvent_ function only when the user use 1 finger.
var panDownEvent = pan.handleDownEvent_;
pan.handleDownEvent_ = function (e) {
if(pan.targetPointers.length >1) return false;
panDownEvent.call(pan,e);
return true;
}
The problem is that when I am using this code from some reason the tiles lazy load stop working only on mobile.
I will be graceful if you can add an api option to limit the pan to only one finger or give me other solution,
or event better, how to trigger the ol lazy load function.
Thanks.

The OpenLayers map is created with some default interactions. The PinchZoom interaction is one of them. Any default interaction can be disabled when creating the map, for example to disable the pinch zoom interaction, you can do this:
var map = new ol.Map({
layers: layers,
interactions: ol.interaction.defaults({
pinchZoom: false
}),
view: new ol.View({
center: [0, 0],
zoom: 2
})
});
Learn more about this in the list of interactions page, which includes details about ol.interaction.defaults, i.e. the list of default interactions in an OpenLayers map.
Try this and see if that makes your other issue disappear.

Related

Google Maps API (bug?) - Mousedown stuck when map hand drag starts on 'to-be-editable' polygon point

My apologies for the subject name, but I believe I've found a relatively easy bug to replicate, in which clicking and dragging on the map in a particular point on a polygon sticks the map into a "mouse-down drag" state that is difficult to get out of.
It's much easier to show this problem. How to recreate:
http://jsfiddle.net/un0a0ua5/
Ensure that polygon is not editable (no point markers on vertices)
Move your cursor to any vertice where the vertice would be shown upon clicking (top right is easiest to reproduce), ensure that it has the 1-finger pointer cursor
Click and drag the mouse like you're scrolling to a different area on the map, let go of the mouse button
You're now stuck like your mouse is still down, moving the map centered on the vertice, the only way to break from it is scrolling the mouse wheel.
I'm not sure if this is a Google Maps bug, or if I should be able to manually trigger a 'mouseup' event on the map to release the hold.
I was able to reproduce this on Chrome and Firefox on Ubuntu, and Chrome on Windows. I can provide more detail if needed.
Any thoughts?
Reproducible from:
var map = new google.maps.Map(document.getElementById("map_div"), {
center: new google.maps.LatLng(33.808678, -117.918921),
zoom: 14,
});
var new_poly = new google.maps.Polygon({
paths: [{lat: 33.808678, lng: -117.916921}, {lat: 33.818678, lng:-117.914921}, {lat: 33.801678, lng:-117.928921}],
strokeColor: '#000000',
fillColor: '#000000'});
google.maps.event.addListener(new_poly, 'mousedown', function() {
console.log('POLYGON->MOUSE_DOWN');
new_poly.setOptions({editable:true});
});
new_poly.setMap(map);
Changing the event to 'mouseup' solves the problem, but it still seems like a Google Maps API v3 bug.

Google maps v3 synchronized drag

I am currently trying to synchronize the movement of two Google Maps on screen when the user drags them.
Currently I am listening to the center_changed event. However that is only called once a drag has been completed, thus the second map only moves after the drag and not during.
My current code looks like this
var mapOptions = {
center: new google.maps.LatLng(52.287373, -1.548609),
zoom: 12,
// streetViewControl: false
disableDefaultUI: true,
// draggable: false,
// disableDoubleClickZoom: false
};
mapOptions["styles"] = dayStyle;
map = new google.maps.Map(document.getElementById("map-canvas"),
mapOptions);
backgroundMap = new google.maps.Map(document.getElementById("background-map"),
mapOptions);
google.maps.event.addListener(map, 'center_changed', function() {
// Set backgroundMap to match actual map
backgroundMap.panTo(map.getCenter());
});
google.maps.event.addListener(map, 'zoom_changed', function() {
// Set backgroundMap zoom to be further out than actual map
backgroundMap.setZoom((map.getZoom()-2 >= 1) ? map.getZoom()-2 : 1);
});
But I really want to create the same effect that http://snazzymaps.com/ has. I've already tried using the bindTo method to link the background map to the foreground map. But that also only updates the background map after the drag is complete.
the drag event is the one you want, but use it in conjunction with center_changed, because panning using the keyboard arrows will not fire the drag event.
It appears that my code does work in desktop environments.
However the maps JS API limits it callback rates in mobile environments (I can only assume it's for performance reasons), and thus only calls center_changed once per drag. Unlike the on desktop where it is call far more frequently.

Javascript OpenLayers before zoom event listener

I am trying to set up OpenLayers to not display the vector layer just before a zoom starts and make it reappear after a zoom ends. I have the zoom ends part already established like this:
map = new OpenLayers.Map('map_element', { eventListeners: { "zoomend": mapEvent}});
function mapEvent(event) {
if(event.type == "zoomend") {
hide_vector_layer();
}
}
But I don't see any kind of event listener for the start of a zoom in the documentation. There is a "movestart" which covers moving, panning, and zoom. Unfortunately, I can't use the "movestart" one, because I don't want the layer to disappear during a pan. You would think there would be a "zoomstart", as there is a "zoomend".
The reason I am trying to do this, is because I don't like how the vector layer zooms at a different rate when using Google Maps as a base layer. It looks wrong, looks like all the features are inaccurate, even though they land in the right place after the zoom is complete.
Any suggestions?
Here is a easy to add the 'BeforeZoom' event to the OpenLayers . Just add the code below to where you created your map object.
map.zoomToProxy = map.zoomTo;
map.zoomTo = function (zoom,xy){
//Your Before Zoom Actions
//If you want zoom to go through call
map.zoomToProxy(zoom,xy);
//else do nothing and map wont zoom
};
How this works:
For any kind of zooming activity, OpenLayers API ultimately calls the function called zoomTo. So before overriding it, we copy that function to a new function called 'zoomToProxy'. The we override it and add our conditional zoom logic. If we want the zoom to happen we just call new proxy function :)
For this purpose you should override moveTo and moveByPx methods of OpenLayers.Map for eliminate movestart event triggering for any actions except zooming.
I had the same problem that OP had, and I tried to solve it with drnextgis's solution. But unfortunately it didn't completely work:: the zoomChanged property in OpenLayers.Map.moveTo evaluates to true not only when the zoom level has changed, but also when the map has been resized.
My map was 100% of the user's browser window, so if they resized the window, the event would be triggered. This was undesirable for me, as I only wanted to trigger the event if the zoom level had actually changed. My solution was to create an new event, called "zoomstart", which I inserted at the top of OpenLayers.Map.moveTo. Here's the code:
var getZoom = this.getZoom();
if ( !!getZoom && !!zoom && this.isValidZoomLevel(zoom) && getZoom != zoom )
this.events.triggerEvent("zoomstart", zoom);
This code will pass the new zoom level to an event listener that is registered to zoomstart, and in my case I determine the map's restrictedExtent and do other stuff based upon the new zoom level.
Peace be with ye.
"movestart" handles "zoomstart". To detect if the zoomstart, try:
map.events.register("movestart",map, function(e) {
if(e.zoomChanged)
{
//zoom start code here
}
});
Solution of "Shaunak" is worked very well for me.
I want to restrict zooming below 11 so edited his code as
if (zoom > 11) {
map.zoomToProxy(zoom, xy);
}

Google Maps zoomOut-Pan-zoomIn animation

I'm wondering how I get a smooth zoom in animation with the Google Maps API.
I have 2 points, one in, let say China, and one in France. When I'm zoomed in on China, and click the button France. I want it to gradually zoom out smooth, one zoom level at the time. When it's zoomed out it should pan to the new location, and then zoom in on the new location one zoom level at the time.
How can I do this?
You need the zoomOut method with the continuous zoom parameter set to do the zoom and the panTo method to do the smooth panning to the new centerpoint.
You can listen to the zoomEnd and moveEnd events on the map object to chain together your zoomOut, panTo and zoomIn methods.
EDIT:
So in the course of implementing a sample for this problem, I discovered that the doContinuousZoom param on ZoomIn and ZoomOut (or just EnableContinuousZoom on the map) doesn't quite work as expected. It works ok when zooming out, if the tiles are in the cache (this is an important point, if the tiles aren't cached then it is not really possible to get the smooth animation you are after) then it does some nice scaling on the tiles to simulate a smooth zoom animation and introduces a ~500 ms delay on each zoom step so you can do it asynchronously (unlike panTo, which you will see in my example I use a setTimeout to call async).
Unfortunately the same is not true for the zoomIn method, which just jumps to the target zoom level without the scaling animation for each zoom level. I haven't tried explicitly setting the version for the google maps code, so this might be something that is fixed in later versions. Anyway, here is the sample code which is mostly just javascript hoop jumping and not so much with the Google Maps API:
http://www.cannonade.net/geo.php?test=geo2
Because this approach seems a bit unreliable, I think it would make more sense to do the async processing for setZoom explicitly (Same as the panning stuff).
EDIT2:
So I do the async zooming explicitly now (using setTimeout with a single zoom at a time). I also have to fire events when each zoom happens so that my events chain correctly. It seems like the zoomEnd and panEnd events are being called synchronously.
Setting enableContinuousZoom on the map doesn't seem to work, so I guess calling zoomOut, zoomIn with the param is the only way to get that to work.
Here's my approach.
var point = markers[id].getPosition(); // Get marker position
map.setZoom(9); // Back to default zoom
map.panTo(point); // Pan map to that position
setTimeout("map.setZoom(14)",1000); // Zoom in after 1 sec
var zoomFluid, zoomCoords; //shared variables
function plotMarker(pos, name){
var marker = new google.maps.Marker({
map: map,
title:name,
animation: google.maps.Animation.DROP,
position: pos
});
google.maps.event.addListener(marker, 'click', function(){
zoomCoords = marker.getPosition(); //Updates shared position var
zoomFluid = map.getZoom(); //Updates shared zoom var;
map.panTo(zoomCoords); //initial pan
zoomTo(); //recursive call
});
}
// increases zoomFluid value at 1/2 second intervals
function zoomTo(){
//console.log(zoomFluid);
if(zoomFluid==10) return 0;
else {
zoomFluid ++;
map.setZoom(zoomFluid);
setTimeout("zoomTo()", 500);
}
}
For the zoom this one worked for me nicely:
function animateMapZoomTo(map, targetZoom) {
var currentZoom = arguments[2] || map.getZoom();
if (currentZoom != targetZoom) {
google.maps.event.addListenerOnce(map, 'zoom_changed', function (event) {
animateMapZoomTo(map, targetZoom, currentZoom + (targetZoom > currentZoom ? 1 : -1));
});
setTimeout(function(){ map.setZoom(currentZoom) }, 80);
}
}

Scalable google maps overlay

Is it possible to add an image overlay to a google map that scales as the user zooms?
My current code works like this:
var map = new GMap2(document.getElementById("gMap"));
var customIcon = new GIcon();
customIcon.iconSize = new GSize(100, 100);
customIcon.image = "/images/image.png";
map.addOverlay(new GMarker(new GLatLng(50, 50), { icon:customIcon }));
However, this adds an overlay that maintains the same size as the user zooms in and out (it is acts as a UI element like the sidebar zoom control).
There is a zoomend event, fired when the map reaches a new zoom level. The event handler receives the previous and the new zoom level as arguments.
http://code.google.com/apis/maps/documentation/reference.html#Events_GMap
You might want to check out openlayers
It's a very capable Javascript API - it supports a bunch of back ends, allowing you to transparently switch between, say, Google Map tiles and Yahoo Map tiles.
Well after messing around trying to scale it myself for a little bit I found a helper called EInserts which I'm going to check out.
Addition:
Okay EInserts is about the coolest thing ever.
It even has a method to allow you to drag the image and place it in development mode for easy lining up.

Categories